Tengo problemas para hacer que mis fragmentos se comuniquen entre sí a través de Activity, que está usando FragmentPagerAdapter, como una clase auxiliar que implementa la gestión de pestañas y todos los detalles de la conexión de un ViewPagerasociado TabHost. He implementado FragmentPagerAdapterlo mismo que lo proporciona el proyecto de ejemplo de Android Support4Demos .
La pregunta principal es ¿cómo puedo obtener un fragmento particular FragmentManagercuando no tengo ni una identificación ni una etiqueta? FragmentPagerAdapterestá creando los fragmentos y generando automáticamente la identificación y las etiquetas.
android
android-fragments
fragmentpageradapter
Ismar Slomic
fuente
fuente

Respuestas:
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 aFragmentStatePagerAdapter.Si está leyendo esto, probablemente ya sepa que
FragmentPagerAdapter/FragmentStatePagerAdapterestá destinado a crearFragmentspara ustedViewPager, 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), estosFragmentsno se crearán nuevamente, sino que instancias recuperadas deFragmentManager. Ahora diga susActivitynecesidades para obtener una referencia a estosFragmentspara trabajar en ellos. No tiene unidotagpara estos creadosFragmentsporque losFragmentPagerAdapterconfiguró 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
FragmentllamandoFragmentManager.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 latagestructura que rompería su código dejándolo incapaz de encontrar una referencia al existenteFragments.Solución alternativa sin depender de internos
tagAquí hay un ejemplo simple de cómo obtener una referencia al
Fragmentsdevuelto porFragmentPagerAdapterque no se basa en eltagsconjunto interno deFragments. La clave es anularinstantiateItem()y guardar referencias allí en lugar de hacerlogetItem().o si prefiere trabajar con
tagsvariables / referencias de miembros de clase en lugar de,Fragmentstambién puede tomar eltagsconjunto deFragmentPagerAdapterla misma manera: NOTA: esto no se aplica aFragmentStatePagerAdapterya que no se establecetagsal crear suFragments.Tenga en cuenta que este método NO se basa en imitar el
tagconjunto interno deFragmentPagerAdaptery, en su lugar, utiliza las API adecuadas para recuperarlos. De esta manera, incluso si lostagcambios en futuras versiones de laSupportLibrary, seguirás estando seguro.No olvide que, dependiendo del diseño de su
Activity, el en elFragmentsque está tratando de trabajar puede o no existir todavía, por lo que debe tenerlo en cuenta haciendonullverificaciones antes de usar sus referencias.Además, si en cambio está trabajando con
FragmentStatePagerAdapter, entonces no desea mantener referencias duras a suFragmentsporque es posible que tenga muchas de ellas y las referencias duras las guardarían innecesariamente en la memoria. En su lugar, guarde lasFragmentreferencias enWeakReferencevariables en lugar de en las estándar. Me gusta esto:fuente
instantiateItem. la forma correcta de hacer esto es llamarinstantiateItemalonCreatemétodo de su actividad rodeado porstartUpdateyfinishUpdate. Vea mi respuesta para más detallesEncontré la respuesta a mi pregunta basada en la siguiente publicación: reutilización de fragmentos en un adaptador de página de fragmentos
Pocas cosas he aprendido:
getItem(int position)en elFragmentPagerAdapternombre bastante engañoso de lo que realmente hace este método. Crea nuevos fragmentos, no devuelve los existentes. En ese sentido, el método debería cambiarse de nombre a algo parecidocreateItem(int position)al SDK de Android. Entonces este método no nos ayuda a obtener fragmentos.FragmentPagerAdaptery, por lo tanto, no tiene ninguna referencia a los Fragmentos o sus etiquetas. Sin embargo, si tiene una etiqueta de fragmento, puede recuperar fácilmente la referencia a ellaFragmentManagerllamandofindFragmentByTag(). Necesitamos una forma de averiguar la etiqueta de un fragmento en la posición de página determinada.Solución
Agregue el siguiente método auxiliar en su clase para recuperar la etiqueta del fragmento y enviarla al
findFragmentByTag()método.¡NOTA! Este es un método idéntico al que se
FragmentPagerAdapterutiliza al crear nuevos fragmentos. Vea este enlace http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104fuente
onAttach()?no necesita anular
instantiateItemni depender de la compatibilidad con elmakeFragmentNamemétodo interno creando manualmente etiquetas de fragmento.instantiateItemEs un público método por lo que puede y de hecho debe llamar enonCreateel método de su actividad rodeado con llamadas astartUpdateyfinishUpdatemétodos descritos en elPagerAdapterjavadoc :Luego, por medio de lo anterior, puede almacenar referencias a instancias de sus fragmentos en vars locales si lo necesita. Ver ejemplo:
instantiateItemprimero intentará obtener referencias a instancias de fragmentos existentes deFragmentManager. Solo si aún no existen, creará nuevos utilizando elgetItemmétodo de su adaptador y los "almacenará" en elFragmentManagerpara cualquier uso futuro.Es importante tener en cuenta que incluso si no necesita obtener referencias a sus fragmentos, aún debe llamar
instantiateItema todas sus pestañas rodeadas porstartUpdate/finishUpdateen suonCreatemétodo de esta manera:Si no lo hace, entonces usted está en riesgo de que sus casos de fragmentos no se comprometen a
FragmentManager: cuando su actividad se convierte en primer planoinstantiateItemse llamará automáticamente para obtener sus fragmentos, perostartUpdate/finishUpdatepueden no (dependiendo de los detalles de implementación) y lo que básicamente hacer es comenzar / confirmar aFragmentTransaction.Esto puede provocar que las referencias a las instancias de fragmentos creadas se pierdan muy rápidamente (por ejemplo, cuando gira la pantalla) y se vuelvan a crear con mucha más frecuencia de la necesaria. Dependiendo de cuán "pesados" sean sus fragmentos, puede tener consecuencias de rendimiento no despreciables.
Además, en tal caso, las instancias de fragmentos almacenados en vars locales puedense vuelve obsoleto: si la plataforma Android intenta obtenerlos
FragmentManagerpor cualquier motivo, fallará y, por lo tanto, creará y usará nuevos, mientras que sus vars seguirán haciendo referencia a los antiguos.fuente
FragmentManagerno puede simplemente matar al azar ( destruir es la palabra correcta aquí) suFragment(piense en lo que sucedería si decidiera matar unFragmentque se está mostrando actualmente;)). En general, el ciclo de vida de aFragmentestá vinculado a suActivity(consulte github.com/xxv/android-lifecycle para obtener más detalles) -> aFragmentsolo se puede destruir siActivityse destruyó. En tal caso, cuando un usuario de vuelta navega a lo dadoActivitysuonCreateserán llamados de nuevo y una nueva instancia de laFragmentse creará.La forma en que lo hice es definir una tabla hash de WeakReferences de la siguiente manera:
Luego escribí el método getItem () así:
Entonces puedes escribir un método:
Esto parece funcionar bien y lo encuentro un poco menos complicado que el
truco, ya que no depende de cómo se implementa FragmentPagerAdapter. Por supuesto, si el fragmento ha sido liberado por FragmentPagerAdapter o si aún no se ha creado, getFragment devolverá un valor nulo.
Si alguien encuentra algún problema con este enfoque, los comentarios son más que bienvenidos.
fuente
int fragmentIddebería cambiarse el nombre aint positionCreé este método que me funciona para obtener una referencia al fragmento actual.
fuente
la solución sugerida por @ personne3000 es agradable, pero tiene un problema: cuando la actividad pasa a un segundo plano y el sistema la elimina (para obtener algo de memoria libre) y luego se restaura,
fragmentReferencesestará vacía, porquegetItemno sería llamado.La siguiente clase maneja tal situación:
fuente
El principal obstáculo para manejar los fragmentos es que no puede confiar en getItem (). Después de un cambio de orientación, las referencias a los fragmentos serán nulas y no se volverá a llamar a getItem ().
Este es un enfoque que no depende de la implementación de FragmentPagerAdapter para obtener la etiqueta. Anule instantiateItem () que devolverá el fragmento creado a partir de getItem () o encontrado desde el administrador de fragmentos.
fuente
Vea esta publicación sobre cómo devolver fragmentos del FragmentPagerAdapter. Depende de que conozca el índice de su fragmento, pero esto se establecería en getItem () (solo en la instanciación)
fuente
Me las arreglé para resolver este problema usando identificadores en lugar de etiquetas. (Estoy usando que definí FragmentStatePagerAdapter que usa mis Fragmentos personalizados en los que anulé el método onAttach, donde guardas la identificación en algún lugar:
Y luego accedes al fragmento fácilmente dentro de la actividad:
fuente
No sé si este es el mejor enfoque, pero nada más funcionó para mí. Todas las demás opciones, incluido getActiveFragment, devolvieron un valor nulo o provocaron que la aplicación se bloqueara.
Noté que en la rotación de la pantalla el fragmento se estaba adjuntando, así que lo usé para enviar el fragmento de regreso a la actividad.
En el fragmento:
Luego en la actividad:
Y finalmente en la actividad onCreate ():
Este enfoque une el fragmento visible real a la actividad sin crear uno nuevo.
fuente
No estoy seguro de si mi método era la mejor o correcta para hacer esto, ya que soy un principiante relativo con Java / Android, pero funcionó (estoy seguro de que viola los principios orientados a objetos, pero ninguna otra solución funcionó para mi caso de uso).
Tuve una actividad de alojamiento que estaba usando un ViewPager con un FragmentStatePagerAdapter. Para obtener referencias a los Fragmentos que fueron creados por FragmentStatePagerAdapter, creé una interfaz de devolución de llamada dentro de la clase de fragmento:
En la actividad de hosting implementé la interfaz y creé un LinkedHasSet para realizar un seguimiento de los fragmentos:
Dentro de la clase ViewPagerFragment agregué los fragmentos a la lista dentro de onAttach y los eliminé dentro de onDetach:
Dentro de la actividad de alojamiento, ahora podrá usar mFragments para iterar a través de los fragmentos que existen actualmente en FragmentStatePagerAdapter.
fuente
Esta clase hace el truco sin depender de etiquetas internas. Advertencia: Se debe acceder a los fragmentos utilizando el método getFragment y no getItem.
fuente
Sigue probando este código,
fuente