Comprender el setRetainInstance de Fragment (boolean)

341

Comenzando con la documentación:

public void setRetainInstance (retención booleana)

Controle si una instancia de fragmento se retiene a través de la recreación de la actividad (como un cambio de configuración). Esto solo se puede usar con fragmentos que no están en la pila posterior. Si se establece, el ciclo de vida del fragmento será ligeramente diferente cuando se recrea una actividad:

  • onDestroy () no se llamará (pero onDetach () aún lo será, porque el fragmento se está separando de su actividad actual).
  • onCreate (Bundle) no se llamará ya que el fragmento no se está volviendo a crear.
  • onAttach (Activity) y onActivityCreated (Bundle) se seguirán llamando.

Tengo algunas preguntas:

  • ¿El fragmento también conserva su vista, o esto se volverá a crear en el cambio de configuración? ¿Qué significa exactamente "retenido"?

  • ¿Se destruirá el fragmento cuando el usuario abandone la actividad?

  • ¿Por qué no funciona con fragmentos en la pila posterior?

  • ¿Cuáles son los casos de uso en los que tiene sentido usar este método?

Ixx
fuente
44
pregunta similar con buena información: ¿Por qué usar Fragment # setRetainInstance (boolean)?
Richard Le Mesurier

Respuestas:

348

En primer lugar, mira mi publicación sobre Fragmentos retenidos. Podría ayudar.

Ahora para responder a sus preguntas:

¿El fragmento también conserva su estado de vista , o se volverá a crear en el cambio de configuración? ¿Qué es exactamente "retenido"?

Sí, el Fragmentestado de 's se retendrá durante el cambio de configuración. Específicamente, "retenido" significa que el fragmento no se destruirá en los cambios de configuración. Es decir, Fragmentse conservará incluso si el cambio de configuración hace Activityque se destruya el subyacente .

¿Se destruirá el fragmento cuando el usuario abandone la actividad?

Al igual que Activitys, Fragments puede ser destruido por el sistema cuando los recursos de memoria son bajos. El hecho de que sus fragmentos conserven su estado de instancia en los cambios de configuración no tendrá ningún efecto sobre si el sistema destruirá o no los Fragments una vez que abandone el Activity. Si abandonas el Activity(es decir, presionando el botón de inicio), el Fragments puede o no destruirse. Si sale Activitypresionando el botón Atrás (por lo tanto, llamando finish()y destruyendo efectivamente Activity), todos los Activitymensajes adjuntos Fragmenttambién se destruirán.

¿Por qué no funciona con fragmentos en la pila posterior?

Probablemente hay varias razones por las que no es compatible, pero la razón más obvia para mí es que Activitytiene una referencia a la FragmentManager, y FragmentManagergestiona la pila. Es decir, no importa si elige retener su correo electrónico Fragmento no, el Activity(y, por lo tanto, el FragmentManagerbackstack) se destruirá en un cambio de configuración. Otra razón por la que podría no funcionar es porque las cosas pueden complicarse si se permite que existan fragmentos retenidos y no retenidos en la misma pila.

¿Cuáles son los casos de uso en los que tiene sentido usar este método?

Los fragmentos retenidos pueden ser bastante útiles para propagar información de estado, especialmente la gestión de subprocesos, a través de instancias de actividad. Por ejemplo, un fragmento puede servir como host para una instancia de Threado AsyncTask, administrando su operación. Consulte mi publicación de blog sobre este tema para obtener más información.

En general, lo trataría de manera similar al uso onConfigurationChangedcon un Activity... no lo use como una venda solo porque es demasiado vago para implementar / manejar un cambio de orientación correctamente. Úselo solo cuando lo necesite.

Alex Lockwood
fuente
37
Los objetos de vista no se retienen, siempre se destruyen en los cambios de configuración.
Markus Junginger
103
Por lo que puedo decir, si tiene setRetainInstance(true), el Fragmentobjeto java, y todo su contenido no se destruye en la rotación, pero la vista se recrea. Eso se onCreatedView()llama de nuevo. Es básicamente la forma en que debería haber funcionado Activitiesdesde Android 1.0. No creo que sea "flojo" usarlo, o usarlo no es "apropiado". De hecho, no puedo ver por qué no es el valor predeterminado, o por qué querrías desactivarlo.
Timmmm
24
Encuentro su explicación para "¿Por qué no funciona con fragmentos en la pila posterior?" difícil de comprender. Pero tal vez soy tonto :(
HGPB
13
@dierre Una actividad puede destruirse de muchas maneras. Por ejemplo, si hace clic en "Atrás", la actividad se destruirá. Si hace clic en "inicio", la actividad se detendrá y en algún momento en el futuro podría destruirse cuando la memoria sea baja. Los mensajes Fragmentretenidos solo se retienen a través de los cambios de configuración, donde la actividad subyacente se destruye y se recrea de inmediato. En todos los demás casos en los que se destruye la actividad, los fragmentos retenidos también se destruirán.
Alex Lockwood
3
@AlexLockwood, puede confirmar lo siguiente: aunque setRetainInstance(true)se use, uno todavía tiene que implementar su propia persistencia ( savedInstanceStateo de otro modo) para poder manejar todos los escenarios: por ejemplo, "tecla de inicio, girar, volver a la aplicación" recrea mi fragmento con el constructor llamada, perdiendo todas las variables de estado. Tengo una AsyncTaskvariable como miembro, por eso quiero retener, ahora, si quiero que funcione, me veo obligado a detener la tarea, guardar el estado y reanudar cuando el usuario regrese. Así que, en general, esta es solo una forma rápida de ayudar con la rotación, pero por lo demás es inútil en general.
TWiStErRob 05 de
28

setRetaininstancesolo es útil cuando activityse destruye y se vuelve a crear debido a un cambio de configuración porque las instancias se guardan durante una llamada a onRetainNonConfigurationInstance. Es decir, si gira el dispositivo, los fragmentos retenidos permanecerán allí (no se destruyen ni se recrean), pero cuando el tiempo de ejecución mata la actividad para recuperar recursos, no queda nada. Cuando presionas el botón Atrás y sales de la actividad, todo se destruye.

Por lo general, uso esta función para guardar el tiempo de cambio de orientación. Di que he descargado un montón de mapas de bits del servidor y cada uno es de 1 MB, cuando el usuario gira accidentalmente su dispositivo, ciertamente no quiero volver a hacer todo el trabajo de descarga. Creo que tengo Fragmentmis mapas de bits y los agrego al administrador y llamo setRetainInstance, todos los mapas de bits siguen ahí, incluso si cambia la orientación de la pantalla.

Suitianshi
fuente
¿Crea fragmentos "solo de datos" (sin ningún widget) solo como soporte para sus mapas de bits o pueden esos fragmentos tener widgets también? He leído algo sobre el peligro de producir pérdidas de memoria cuando el fragmento contiene algo relacionado con el contexto / Actividad ...
hgoebl
El marco borrará la mActivityreferencia para usted. Pero no sé si el tiempo de ejecución también eliminaría widgets en la instancia de fragmento en este caso. Pruébalo o sumérgete en el código fuente.
suitianshi
Buen ejemplo de cuándo podemos usar el setRetaininstance
Mu Sa
12

SetRetainInstance (true) permite que el fragmento sobreviva. Sus miembros serán retenidos durante el cambio de configuración como la rotación. Pero aún puede ser eliminado cuando la actividad se elimina en segundo plano. Si el sistema elimina la actividad que contiene en segundo plano, el sistema que manejó en SaveInstanceState debe guardar su instancia de StateState correctamente. En otras palabras, siempre se llamará a onSaveInstanceState. Aunque onCreateView no se invocará si SetRetainInstance es verdadero y el fragmento / actividad aún no se elimina, aún se invocará si se eliminó y se intenta recuperarlo.

Aquí hay un análisis de la actividad / fragmento de Android espero que ayude. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html

Kejun Xia
fuente
8
Definitivamente estoy viendo que onCreateView es llamado nuevamente en el fragmento retenido al girar la pantalla.
aij
¿Es este enlace tu propio blog? Deberías dejar eso claro si ese es el caso.
Flexo
4

setRetainInstance () - Desaprobado

As Fragments Version 1.3.0-alpha01

El método setRetainInstance () en Fragments ha quedado en desuso. Con la introducción de ViewModels, los desarrolladores tienen una API específica para retener el estado que se puede asociar con gráficos de Actividades, Fragmentos y Navegación. Esto permite a los desarrolladores usar un Fragmento normal no retenido y mantener el estado específico que desean retener por separado, evitando una fuente común de fugas y manteniendo las propiedades útiles de una sola creación y destrucción del estado retenido (es decir, el constructor del ViewModel y la devolución de llamada onCleared () que recibe).

Gastón Saillén
fuente
2

setRetainInstance (boolean) es útil cuando desea tener algún componente que no esté vinculado al ciclo de vida de la actividad. Por ejemplo, rxloader utiliza esta técnica para "manejar el ciclo de vida de la actividad de Android para el Observable de rxjava" (que he encontrado aquí ).

Marian Paździoch
fuente