Ciclo de vida de los fragmentos

Cada instancia de Fragment tiene su propio ciclo de vida. Cuando un usuario navega por tu app e interactúa con ella, los fragmentos pasan por varios estados durante su ciclo de vida a medida que se agregan, se quitan e ingresan a la pantalla o salen de ella.

Para administrar el ciclo de vida, Fragment implementa LifecycleOwner, lo que expone un objeto Lifecycle al que puedes acceder a través del método getLifecycle().

En la enumeración Lifecycle.State, se representa cada estado posible de Lifecycle.

Si compilas Fragment sobre Lifecycle, puedes usar las técnicas y clases disponibles para administrar ciclos de vida con componentes optimizados para estos. Uno de estos componentes te permite mostrar la ubicación del dispositivo en la pantalla. Ese componente podría comenzar a escuchar automáticamente cuando el fragmento se active y detenerse cuando este pase a un estado inactivo.

Como alternativa al uso de un LifecycleObserver, la clase de Fragment incluye métodos de devolución de llamada que corresponden a cada uno de los cambios en el ciclo de vida de un fragmento. Se incluyen los siguientes: onCreate(), onStart(), onResume(), onPause(), onStop() y onDestroy().

La vista de un fragmento tiene un Lifecycle separado que se administra de forma independiente del Lifecycle del fragmento. Los fragmentos mantienen un LifecycleOwner para su vista, al que se puede acceder con getViewLifecycleOwner() o getViewLifecycleOwnerLiveData(). Tener acceso al Lifecycle de la vista es útil para situaciones en las que un componente optimizado para ciclos de vida solo deba realizar trabajos mientras exista la vista de un fragmento, como observar LiveData que solo debe mostrarse en la pantalla.

En este tema, se analiza en detalle el ciclo de vida de Fragment, se explican algunas de las reglas que determinan el estado del ciclo de vida de un fragmento y se muestra la relación entre los estados de Lifecycle y las devoluciones de llamada de ciclo de vida de los fragmentos.

Los fragmentos y el administrador de fragmentos

Cuando se crea una instancia de un fragmento, este comienza en el estado INITIALIZED. Para que un fragmento pase por el resto de su ciclo de vida, se lo debe agregar a un FragmentManager. El FragmentManager se encarga de determinar el estado que debe tener su fragmento y, luego, de pasarlo a ese estado.

Más allá del ciclo de vida del fragmento, FragmentManager también se encarga de adjuntar fragmentos a su actividad de host y de separarlos cuando el fragmento ya no esté en uso. La clase Fragment tiene dos métodos de devolución de llamada, onAttach() y onDetach(), que puedes anular para realizar trabajos cuando se produce cualquiera de estos eventos.

Cuando se agrega el fragmento a un FragmentManager, se invoca la devolución de llamada onAttach() y se la adjunta a su actividad de host. En este punto, el fragmento está activo y el FragmentManager administra su estado de ciclo de vida. Asimismo, los métodos de FragmentManager como findFragmentById() muestran este fragmento.

Siempre se llama a onAttach() antes de cualquier cambio de estado de ciclo de vida.

Cuando se quita el fragmento de un FragmentManager, se invoca la devolución de llamada onDetach() y se la desconecta de su actividad de host. El fragmento ya no está activo y ya no se puede recuperar con findFragmentById().

Siempre se llama a onDetach() después de cualquier cambio de estado de ciclo de vida.

Ten en cuenta que estas devoluciones de llamada no están relacionadas con los métodos attach() ni detach() de FragmentTransaction. Para obtener más información sobre estos métodos, consulta Transacciones de fragmentos.

Estados del ciclo de vida de los fragmentos y devoluciones de llamada

A la hora de determinar el estado del ciclo de vida de un fragmento, FragmentManager tiene en cuenta lo siguiente:

  • FragmentManager determina el estado máximo de un fragmento. Un fragmento no puede avanzar más allá del estado de su FragmentManager.
  • Como parte de una FragmentTransaction, puedes configurar un estado de ciclo de vida máximo para un fragmento con setMaxLifecycle().
  • El estado de ciclo de vida de un fragmento nunca puede ser mayor que su elemento superior. Por ejemplo, una actividad o un fragmento superior deben iniciarse antes que sus fragmentos secundarios. Del mismo modo, los fragmentos secundarios deben detenerse antes de que lo hagan sus fragmentos o actividades superiores.
Estados de ciclo de vida del fragmento y su relación tanto con las devoluciones de llamada de ciclo de vida del fragmento como con el ciclo de vida de la vista del fragmento
Figura 1: Estados de Lifecycle del fragmento y su relación tanto con las devoluciones de llamada del ciclo de vida del fragmento como con el Lifecycle de la vista del fragmento.

En la Figura 1, se muestra cada uno de los estados de Lifecycle del fragmento y la forma en la que se relacionan con las devoluciones de llamada de su ciclo de vida y con el Lifecycle de su vista.

A medida que un fragmento avanza por su ciclo de vida, se mueve de manera ascendente y descendente por sus estados. Por ejemplo, un fragmento que se agrega a la parte superior de la pila de actividades se mueve de manera ascendente de CREATED a STARTED y a RESUMED. En cambio, cuando un fragmento se quita de la pila de actividades, se mueve de manera descendente por esos estados, de RESUMED a STARTED, luego a CREATED y, por último, a DESTROYED.

Transiciones de estado ascendentes

Cuando un fragmento se mueve por los estados de su ciclo de vida, primero llama a la devolución de llamada de ciclo de vida asociada a su estado nuevo. Una vez que finaliza la devolución de llamada, se transmite el Lifecycle.Event correspondiente a los observadores por el Lifecycle del fragmento, seguido del Lifecycle de la vista del fragmento, si se creó su instancia.

Fragmento CREADO

Cuando tu fragmento alcanza el estado CREATED, significa que se lo agregó a un FragmentManager y ya se llamó al método onAttach().

Este sería el lugar adecuado para restablecer el estado guardado asociado con el fragmento a través de su SavedStateRegistry. Ten en cuenta que la vista del fragmento aún no se creó, y cualquier estado asociado con la vista del fragmento debe restablecerse solo después de que se haya creado la vista.

Esta transición invoca la devolución de llamada onCreate(). Esta también recibe un argumento savedInstanceState Bundle que contiene cualquier estado guardado con anterioridad por onSaveInstanceState(). Ten en cuenta que savedInstanceState tiene un valor null la primera vez que se crea el fragmento, pero siempre es no nulo para las recreaciones posteriores, incluso si no anulas onSaveInstanceState(). Consulta Cómo guardar estados con fragmentos para obtener más detalles.

Fragmento CREADO y vista INICIALIZADA

El Lifecycle de la vista del fragmento solo se crea cuando tu Fragment proporciona una instancia válida de View. En la mayoría de los casos, puedes usar los constructores de fragmentos que toman un @LayoutId, lo que aumenta automáticamente la vista en el momento apropiado. También puedes anular onCreateView() para aumentar o crear de manera programática la vista del fragmento.

Siempre y cuando se cree una instancia de la vista del fragmento con una View no nula, esa View se establece en el fragmento y se puede recuperar con getView(). Luego, el getViewLifecycleOwnerLiveData() se actualiza con el LifecycleOwner recientemente INITIALIZED, que corresponde a la vista del fragmento. La devolución de llamada del ciclo de vida de onViewCreated() también se llama en ese momento.

Este es el lugar adecuado para configurar el estado inicial de la vista a fin de comenzar a observar instancias de LiveData, cuyas devoluciones de llamada actualizan la vista del fragmento, y también para configurar los adaptadores en cualquier instancia de RecyclerView o ViewPager2, en la vista del fragmento.

Fragmento y vista CREADOS

Después de crear la vista del fragmento, se restablece el estado anterior de la vista, si existe, y el Lifecycle de la vista pasa al estado CREATED. El propietario del ciclo de vida de la vista también emite el evento ON_CREATE a sus observadores. Aquí debes restablecer cualquier estado adicional asociado con la vista del fragmento.

Esta transición también invoca la devolución de llamada onViewStateRestored().

Fragmento y vista COMENZADOS

Se recomienda que vincules los componentes optimizados para ciclos de vida al estado STARTED de un fragmento, ya que este estado garantiza que la vista del fragmento, si se creó alguna, esté disponible y que sea seguro realizar una FragmentTransaction en el FragmentManager secundario del fragmento. Si la vista del fragmento no es nula, el Lifecycle de la vista del fragmento pasa a STARTED inmediatamente después de que el Lifecycle del fragmento pase a STARTED.

Cuando el fragmento pasa a STARTED, se invoca la devolución de llamada onStart().

Fragmento y vista REANUDADOS

Cuando el fragmento sea visible, habrán finalizado todos los efectos de Animator y Transition, y el fragmento estará listo para la interacción del usuario. El Lifecycle del fragmento pasa al estado RESUMED y se invoca la devolución de llamada onResume().

La transición a RESUMED es la señal correspondiente que indica que el usuario ahora puede interactuar con el fragmento. Los fragmentos que no tengan el estado RESUMED no deben establecer manualmente el foco en sus vistas ni intentar controlar la visibilidad del método de entrada.

Transiciones de estado descendentes

Cuando un fragmento se mueve hacia un estado inferior del ciclo de vida, el Lifecycle de la vista del fragmento, si se creó una instancia de esta, emite el Lifecycle.Event correspondiente a los observadores, seguido del Lifecycle del fragmento. Después de que se emite el evento del ciclo de vida de un fragmento, este último llama a la devolución de llamada de ciclo de vida asociada.

Fragmento y vista COMENZADOS

Cuando el usuario comienza a dejar el fragmento y mientras este aún está visible, los Lifecycle del fragmento y de su vista vuelven a pasar al estado STARTED y a emitir el evento ON_PAUSE a sus observadores. Luego, el fragmento invoca su devolución de llamada onPause().

Fragmento y vista CREADOS

Una vez que el fragmento ya no esté visible, los Lifecycle del fragmento y de su vista pasarán al estado CREATED y emitirán el evento ON_STOP a sus observadores. Esta transición de estado se activa no solo cuando se detiene la actividad o el fragmento superiores, sino también cuando alguno de ellos guarda un estado. Este comportamiento garantiza que el evento ON_STOP se invoque antes de que se guarde el estado del fragmento. Esto hace que el evento ON_STOP sea el último punto en el que es seguro realizar una FragmentTransaction en el FragmentManager secundario.

Como se muestra en la Figura 2, el orden de la devolución de llamada onStop() y el guardado del estado con onSaveInstanceState() difieren según el nivel de API. En todos los niveles de API anteriores a la API 28, onSaveInstanceState() se invoca antes de onStop(). En el caso de los niveles de API 28 y posteriores, el orden de llamada está invertido.

Diferencias en el orden de las llamadas a onStop() y onSaveInstanceState()
Figura 2: Diferencias en el orden de las llamadas para onStop() y onSaveInstanceState().

Fragmento CREADO y vista DESTRUIDA

Una vez que se completaron todas las animaciones y transiciones de salida y que la vista del fragmento se separó de la ventana, el Lifecycle de la vista del fragmento pasa al estado DESTROYED y emite el evento ON_DESTROY a sus observadores. Luego, el fragmento invoca su devolución de llamada onDestroyView(). En este punto, la vista del fragmento alcanzó el final de su ciclo de vida y getViewLifecycleOwnerLiveData() muestra un valor null.

Asimismo, se deben quitar todas las referencias a la vista del fragmento, lo que permitirá la recolección de elementos no utilizados.

Fragmento DESTRUIDO

Si se quita el fragmento, o si se destruye el FragmentManager, el Lifecycle del fragmento pasa al estado DESTROYED y envía el evento ON_DESTROY a sus observadores. Luego, el fragmento invoca su devolución de llamada onDestroy(). En este punto, el fragmento alcanzó el final de su ciclo de vida.

Recursos adicionales

Para obtener más información relacionada con el ciclo de vida de los fragmentos, consulta los siguientes recursos adicionales.

Guías

Blogs