2012-01-21 4 views
21

Ho un ViewPager e utilizza uno FragmentAdapter per visualizzare diversi frammenti dello stesso tipo. Sebbene questi frammenti siano fondamentalmente istanziati dalla stessa classe, stanno utilizzando un ListView per visualizzare informazioni diverse. (Ovviamente lo ListView è in fase di caricamento da ArrayAdapter.)
Un servizio in background è in esecuzione e riceve costantemente dati da Internet. Desidero poter aggiornare un frammento specifico nello ViewPager quando il mio servizio in background mi ha informato di un evento specifico.
Come posso farlo? Uno snippet di codice sarebbe molto apprezzato!Attività ViewPager per notificare un frammento di un evento specifico

(A proposito, ho sega this similar question ma non ho idea di come usare il loro suggerimento!)

Per rendere il tutto più semplice: La mia attività con la ViewPager:
[Frammento 0] [Frammento 1] [Frammento 2]

il servizio in background mi dice (tramite una trasmissione) per aggiornare il ListView in Frammento 1.

EDIT: Qui ci sono codici di esempio:

public class ChatWindowPager extends FragmentActivity 
{ 
    private ViewPager mViewPager = null; 
    private ChatFragmentAdapter mAdapter = null; 
    @Override 
    protected void onCreate(final Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.chat_window_pager); 

     this.mViewPager = (ViewPager) findViewById(R.id.chatPager); 
     this.mAdapter = new ChatFragmentAdapter(getSupportFragmentManager()); 
     this.mViewPager.setAdapter(this.mAdapter); 
     . 
     . 
     . 
    } 

    class ChatFragmentAdapter extends FragmentPagerAdapter implements ViewProvider 
    { 

     public ChatFragmentAdapter(final FragmentManager fm) 
     { 
      super(fm); 
     } 

     @Override 
     public Fragment getItem(final int arg0) 
     { 
      String friendId = ..... // Some initializations 
      ChatWindowFragment f = ChatWindowFragment.newInstance(friendId); 
      return f; 
     } 

     @Override 
     public int getCount() 
     { 
      ... 
     } 

     @Override 
     public View getView(final int position) 
     { 
      View v = getLayoutInflater().inflate(R.layout.tab_holder, null); 
      . 
      . 
      . 
      return v; 
     } 
    } 
} 

Ora i frammenti è definita in questo modo:

public class ChatWindowFragment extends Fragment 
{ 
    public String friendId; 
    private ListView lv; 

    public static ChatWindowFragment newInstance(final String friendId) 
    { 
     ChatWindowFragment chatWindowFragment = new ChatWindowFragment(); 
     Bundle bundle = new Bundle(); 
     bundle.putString("friendId", friendId); 
     chatWindowFragment.setArguments(bundle); 
     return chatWindowFragment; 
    } 

    @Override 
    public void onCreate(final Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     this.friendId = getArguments().getString("friendId"); 
    } 

    @Override 
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) 
    { 
     View v = inflater.inflate(R.layout.chat_window, container, false); 

     this.friendId = getArguments().getString("friendId"); 
     . 
     . 
     . 
     return v; 
    } 

    //The rest of the class 

} 

Come sto usando un FragmentPagerAdapter non vedo come posso imposta il tag di ogni frammento! (Ovviamente, non sto usando le operazioni per aggiungere i Frammenti!)

EDIT 2: Vorrei sapere se quello che sto facendo, è il modo corretto di gestire quello che voglio fare .. Qualsiasi altra soluzione è anche benvenuta!

+0

hai provato quello che ho suggerito .... –

risposta

38

Prova questo,

registrare un ricevitore di broadcast in tutte le vostre frammenti ... come questo

creare una classe che si estende un ricevitore di broadcast in tutte le classi, per esempio:

public class FragmentReceiver1 extends BroadcastReceiver { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
     }  
} 

e registra questo ricevitore nel frammento di onCreate ...

per es. getActivity().registerReceiver(new FragmentReceiver1(), new IntentFilter("fragmentupdater"));

Ora Assegnare un ID univoco a ciascuno di voi frammentare come 1 per Fragment1, 2 per Fragment2 e allo stesso modo

ora ogni volta che si desidera passare tutti i dati e aggiornare qualsiasi del frammento è sufficiente inviare una trasmissione con i dati negli intenti e "fragmentupdater", come l'intento filtro ...

per esempio:

Intent data = new Intent("fragmentupdater"); 
data.putString("key","data"); 
data.putInt("fragmentno",1); // Pass the unique id of fragment we talked abt earlier 
activity.sendBroadcast(data); 

Ora ognuno dei tuoi frammento riceveranno i dati, ma si può verificare se i dati se per lo stesso frammento di l'unico id noi passato in esso nella funzione onReceive ..., l'intento che si ottiene, è l'intento siamo passati sopra

+13

Se non si utilizzano più processi, considerare l'uso di http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html anziché di trasmissioni globali. Naturalmente puoi sempre implementare il tuo schema di osservatore per far sì che il registro dei frammenti con il servizio venga detto quando avviene un cambiamento a cui è interessato. – hackbod

+1

@King RV Ti ho assegnato la taglia e ho suggerito una modifica per il tuo post! Grazie ... Ciò che hai suggerito è di completare il lavoro, mi chiedo se esiste una soluzione migliore/più semplice per questo problema! Grazie ancora – M2X

+0

Questa è una soluzione davvero complicata (anche se funziona). C'è una soluzione più semplice per ricaricare il contenuto di viewpager? Ad esempio, rimuovere tutte le visualizzazioni figlio e caricarle nuovamente. –

5

Hai provato FragmentManager.findFragmentByTag()

FragmentManager manager = getSupportedFragmentManager(); 
//with support package, else 
//FragmentManager manager = getFragmentManager() 
Fragment fragment = manager.findFragmentByTag("Tag You Created the Fragment"); 
if (fragment instanceof Fragment1){ 
    Fragment1 fr = (Fragment1)fragment 
    fr.updateData(DATA) 
    //or any method of your choice 
} 

EDIT: Ho letto con attenzione! Il instanceOf invierà un Fragment nella classe Fragment. Sei stato tu a suggerire Fragment1 come un nome per la semplicità. Inoltre, non hai fornito alcuna fonte per aiutarci. È vero che non è possibile impostare un tag di Fragment, ma perché pensi di essere in grado di ottenere il suo tag? Di solito un Fragment viene aggiunto attraverso FragmentManagers come

FragmentManager manager = getSupportedFragmnentManager() 
FragmentTransaction transaction = manager.beginTransaction(); 
transaction.add(int containerViewId, Fragment fragment, String tag); 
// or transaction.add(Fragment fragment, String tag) 
// ...other transactions 
transaction.commit() 

EDIT2: è molto facile però. secondo il vostro codice si può solo chiamare

Fragment fragment = mAdapter.getItem(0) // 0||1||2 

Si dovrebbe considerare la lettura dei documenti (cioè circa FragmenPagerAdapter) e pubblicare il tuo codice sorgente in modo da non abbiamo di indovinare che cosa avete bisogno.

+0

Hai letto attentamente la mia domanda? Ho detto, tutti i frammenti sono istanziati dalla stessa classe! Quindi ovviamente non posso usare "instanceof". Inoltre, per quanto ne so, non esiste un metodo "setTag()" disponibile sul frammento. Quindi potrei non essere in grado di inizializzare un frammento usando un tag! Qualsiasi aiuto è molto apprezzato! – M2X

+0

Guarda la parte di modifica! Ancora non so cosa fare, ogni suggerimento è molto apprezzato! – M2X

0

Non so abbastanza di ciò che si sta facendo, ma sembra che sia necessario utilizzare un pattern Observer, callback o listener. Il tuo frammento non può fare qualcosa del genere:

myservice.addMyEventListener(myFragInstance); 

e quindi puoi essere "avvisato di un evento specifico".

+0

Suona bene ... Cura di elaborare? – M2X

0

Basta guardare a questa risposta https://stackoverflow.com/a/16388650

Ha usato yourAdapter.notifyDataSetChanged() che è un metodo predefinito. Controllare il link per vedere come il suo fare

Edit: Quando l'AsyncTask è fatto, si dovrebbe fare qualcosa di simile a questo metodo OnPostExecute:

ResultFragment resultFrag = (ResultFragment) getSupportFragmentManager() 
           .findFragmentByTag("FragToRefresh"); 
if (resultFrag != null) { 
    resultFrag.refreshData(refreshedArray); 
} 

E nel tuo ResultFragment è necessario avere il metodo RefreshData, che è qualcosa di simile:

public void refreshData(ArrayList<YourObject> data) { 
    yourArray = new ArrayList<YourObject>(data); 
    yourAdapter.notifyDataSetChanged(); 
} 
+0

Si consiglia sempre di scrivere possibilmente risposte "autonome" - contenenti una soluzione al problema, non semplicemente il collegamento ad un'altra risposta. Forse una modifica per includere lo snippet più pertinente? :) – bardzusny

2

ho avuto lo stesso problema, ma riparato con un localBroadcastReceiver in questo modo:

Creare un ricevitore nella vostra attività e registrarlo:

/** 
* ****************************** 
* Receiver to process the message 
* ******************************* 
*/ 
private BroadcastReceiver onNotice = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     //You can send any extra data if you need like this 
     final int type = intent.getIntExtra("fragment.data", -1); 
     Log.d(tag, "main class: " + type); 
     //also refresh your fragment like this 
     mViewPager.getViewPager().getAdapter().notifyDataSetChanged(); 
    } 
};  

@Override 
protected void onResume() { 
    super.onResume(); 

    //Register a localbroadCast with the your filter 
    IntentFilter thinaireFilter = new IntentFilter("your.filter"); 
    LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, thinaireFilter); 
} 

Ricordarsi di togliere LocalBroadCast

//remove the LocalBroadCast when no need it 
@Override 
protected void onPause() { 
    super.onPause(); 
    LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice); 
} 
@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice); 
} 

Invia la tua trasmissione da qualsiasi luogo si vuole adattatori, i servizi, ecc

Intent sendBroadCastData = new Intent("your.filter"); 
sendBroadCastData.putExtra("fragment.data", myData); 
LocalBroadcastManager.getInstance(context).sendBroadcast(sendBroadCastData); 

Spero che aiuti gli altri.