Riepilogo del problema
Nota: in questa risposta farò riferimento FragmentPagerAdaptere il suo codice sorgente. Ma la soluzione generale dovrebbe applicarsi anche a FragmentStatePagerAdapter.
Se stai leggendo questo, probabilmente sai già che FragmentPagerAdapter/ FragmentStatePagerAdapterè pensato per creare Fragmentsper te ViewPager, ma durante la ricreazione dell'attività (sia da una rotazione del dispositivo o dal sistema che uccide la tua app per riguadagnare memoria) questi Fragmentsnon verranno creati di nuovo, ma invece il loro istanze recuperate daFragmentManager . Ora dì che hai Activitybisogno di ottenere un riferimento a questi Fragmentsper lavorare su di loro. Non hai creato un ido tagper questi Fragmentsperché FragmentPagerAdapter impostali internamente . Quindi il problema è come ottenere un riferimento a loro senza queste informazioni ...
Problema con le soluzioni attuali: affidarsi al codice interno
Molte delle soluzioni che ho visto su questo e simili domande si basano su come ottenere un riferimento al esistente Fragmentchiamando FragmentManager.findFragmentByTag()e imitando il tag creato internamente:"android:switcher:" + viewId + ":" + id . Il problema con questo è che ti affidi al codice sorgente interno, che come tutti sappiamo non è garantito che rimanga lo stesso per sempre. Gli ingegneri Android di Google potrebbero facilmente decidere di modificare la tagstruttura che romperebbe il codice lasciandoti incapace di trovare un riferimento all'esistente Fragments.
Soluzione alternativa senza fare affidamento sull'interno tag
Ecco un semplice esempio di come ottenere un riferimento al Fragmentsrestituito da FragmentPagerAdapterche non si basa sull'insieme interno tagssu Fragments. La chiave è sovrascrivere instantiateItem()e salvare i riferimenti lì invece che in getItem().
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
o se preferisci lavorare con tagsvariabili / riferimenti al membro della classe invece Fragmentsche puoi anche prendere l' tagsinsieme da FragmentPagerAdapternello stesso modo: NOTA: questo non si applica a FragmentStatePagerAdapterpoiché non si imposta tagsdurante la creazione del suo Fragments.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
Si noti che questo metodo NON si basa sull'imitazione tagdell'insieme interno di FragmentPagerAdaptere utilizza invece API appropriate per il recupero. In questo modo anche se le tagmodifiche nelle future versioni di SupportLibrarysarai comunque al sicuro.
Non dimenticare che, a seconda del design del tuo Activity, quello su Fragmentscui stai cercando di lavorare può o non può ancora esistere, quindi devi tenerne conto facendo nullcontrolli prima di utilizzare i tuoi riferimenti.
Inoltre, se invece stai lavorando con FragmentStatePagerAdapter, allora non vuoi mantenere riferimenti rigidi al tuo Fragmentsperché potresti averne molti e riferimenti rigidi li terrebbero inutilmente in memoria. Salvare invece i Fragmentriferimenti in WeakReferencevariabili anziché in quelli standard. Come questo:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}