Resumen del problema
Nota: En esta respuesta voy a hacer referencia FragmentPagerAdaptery su código fuente. Pero la solución general también debería aplicarse a FragmentStatePagerAdapter.
Si está leyendo esto, probablemente ya sepa que FragmentPagerAdapter/ FragmentStatePagerAdapterestá destinado a crear Fragmentspara usted ViewPager, pero después de la recreación de la actividad (ya sea desde la rotación de un dispositivo o el sistema matando su aplicación para recuperar memoria), estos Fragmentsno se crearán nuevamente, sino que instancias recuperadas deFragmentManager . Ahora diga sus Activitynecesidades para obtener una referencia a estos Fragmentspara trabajar en ellos. No tiene un ido tagpara estos creados Fragmentsporque los FragmentPagerAdapter configuró internamente . Entonces, el problema es cómo obtener una referencia a ellos sin esa información ...
Problema con las soluciones actuales: confiar en el código interno
Muchas de las soluciones que he visto en esta y otras preguntas similares se basan en conseguir una referencia a la existente Fragmentllamando FragmentManager.findFragmentByTag()e imitando la etiqueta creada internamente:"android:switcher:" + viewId + ":" + id . El problema con esto es que está confiando en el código fuente interno, que como todos sabemos no garantiza que siga siendo el mismo para siempre. Los ingenieros de Android en Google podrían decidir fácilmente cambiar la tagestructura que rompería su código dejándolo incapaz de encontrar una referencia al existente Fragments.
Solución alternativa sin depender de internos tag
Aquí hay un ejemplo simple de cómo obtener una referencia al Fragmentsdevuelto por FragmentPagerAdapterque no se basa en el tagsconjunto interno de Fragments. La clave es anular instantiateItem()y guardar referencias allí en lugar de hacerlogetItem() .
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 si prefiere trabajar con tagsvariables / referencias de miembros de clase en lugar de, Fragmentstambién puede tomar el tagsconjunto de FragmentPagerAdapterla misma manera: NOTA: esto no se aplica a FragmentStatePagerAdapterya que no se establece tagsal crear su 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;
}
Tenga en cuenta que este método NO se basa en imitar el tagconjunto interno de FragmentPagerAdaptery, en su lugar, utiliza las API adecuadas para recuperarlos. De esta manera, incluso si los tagcambios en futuras versiones de la SupportLibrary, seguirás estando seguro.
No olvide que, dependiendo del diseño de su Activity, el en el Fragmentsque está tratando de trabajar puede o no existir todavía, por lo que debe tenerlo en cuenta haciendo nullverificaciones antes de usar sus referencias.
Además, si en cambio está trabajando con FragmentStatePagerAdapter, entonces no desea mantener referencias duras a su Fragmentsporque es posible que tenga muchas de ellas y las referencias duras las guardarían innecesariamente en la memoria. En su lugar, guarde las Fragmentreferencias en WeakReferencevariables en lugar de en las estándar. Me gusta esto:
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...
}