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 ViewPager
asociado TabHost
. He implementado FragmentPagerAdapter
lo mismo que lo proporciona el proyecto de ejemplo de Android Support4Demos .
La pregunta principal es ¿cómo puedo obtener un fragmento particular FragmentManager
cuando no tengo ni una identificación ni una etiqueta? FragmentPagerAdapter
está 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
FragmentPagerAdapter
y su código fuente. Pero la solución general también debería aplicarse aFragmentStatePagerAdapter
.Si está leyendo esto, probablemente ya sepa que
FragmentPagerAdapter
/FragmentStatePagerAdapter
está destinado a crearFragments
para 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), estosFragments
no se crearán nuevamente, sino que instancias recuperadas deFragmentManager
. Ahora diga susActivity
necesidades para obtener una referencia a estosFragments
para trabajar en ellos. No tiene unid
otag
para estos creadosFragments
porque losFragmentPagerAdapter
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
Fragment
llamandoFragmentManager.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 latag
estructura que rompería su código dejándolo incapaz de encontrar una referencia al existenteFragments
.Solución alternativa sin depender de internos
tag
Aquí hay un ejemplo simple de cómo obtener una referencia al
Fragments
devuelto porFragmentPagerAdapter
que no se basa en eltags
conjunto interno deFragments
. La clave es anularinstantiateItem()
y guardar referencias allí en lugar de hacerlogetItem()
.o si prefiere trabajar con
tags
variables / referencias de miembros de clase en lugar de,Fragments
también puede tomar eltags
conjunto deFragmentPagerAdapter
la misma manera: NOTA: esto no se aplica aFragmentStatePagerAdapter
ya que no se establecetags
al crear suFragments
.Tenga en cuenta que este método NO se basa en imitar el
tag
conjunto interno deFragmentPagerAdapter
y, en su lugar, utiliza las API adecuadas para recuperarlos. De esta manera, incluso si lostag
cambios en futuras versiones de laSupportLibrary
, seguirás estando seguro.No olvide que, dependiendo del diseño de su
Activity
, el en elFragments
que está tratando de trabajar puede o no existir todavía, por lo que debe tenerlo en cuenta haciendonull
verificaciones antes de usar sus referencias.Además, si en cambio está trabajando con
FragmentStatePagerAdapter
, entonces no desea mantener referencias duras a suFragments
porque es posible que tenga muchas de ellas y las referencias duras las guardarían innecesariamente en la memoria. En su lugar, guarde lasFragment
referencias enWeakReference
variables en lugar de en las estándar. Me gusta esto:fuente
instantiateItem
. la forma correcta de hacer esto es llamarinstantiateItem
alonCreate
método de su actividad rodeado porstartUpdate
yfinishUpdate
. 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 elFragmentPagerAdapter
nombre 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.FragmentPagerAdapter
y, 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 ellaFragmentManager
llamandofindFragmentByTag()
. 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
FragmentPagerAdapter
utiliza 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
instantiateItem
ni depender de la compatibilidad con elmakeFragmentName
método interno creando manualmente etiquetas de fragmento.instantiateItem
Es un público método por lo que puede y de hecho debe llamar enonCreate
el método de su actividad rodeado con llamadas astartUpdate
yfinishUpdate
métodos descritos en elPagerAdapter
javadoc :Luego, por medio de lo anterior, puede almacenar referencias a instancias de sus fragmentos en vars locales si lo necesita. Ver ejemplo:
instantiateItem
primero intentará obtener referencias a instancias de fragmentos existentes deFragmentManager
. Solo si aún no existen, creará nuevos utilizando elgetItem
método de su adaptador y los "almacenará" en elFragmentManager
para cualquier uso futuro.Es importante tener en cuenta que incluso si no necesita obtener referencias a sus fragmentos, aún debe llamar
instantiateItem
a todas sus pestañas rodeadas porstartUpdate
/finishUpdate
en suonCreate
mé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 planoinstantiateItem
se llamará automáticamente para obtener sus fragmentos, perostartUpdate
/finishUpdate
pueden 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
FragmentManager
por cualquier motivo, fallará y, por lo tanto, creará y usará nuevos, mientras que sus vars seguirán haciendo referencia a los antiguos.fuente
FragmentManager
no puede simplemente matar al azar ( destruir es la palabra correcta aquí) suFragment
(piense en lo que sucedería si decidiera matar unFragment
que se está mostrando actualmente;)). En general, el ciclo de vida de aFragment
está vinculado a suActivity
(consulte github.com/xxv/android-lifecycle para obtener más detalles) -> aFragment
solo se puede destruir siActivity
se destruyó. En tal caso, cuando un usuario de vuelta navega a lo dadoActivity
suonCreate
serán llamados de nuevo y una nueva instancia de laFragment
se 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 fragmentId
debería cambiarse el nombre aint position
Creé 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,
fragmentReferences
estará vacía, porquegetItem
no 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