Resumen: en este tutorial verás cómo aislar acciones de los controladores del ciclo de vida de actividades y fragmentos con el paquete androix.lifecycle y sus componentes LifecycleOwner
y LifecycleObserver
.
Qué Son Lifecycle-aware components
Son aquellos que realizan acciones cuando otro componente con ciclo de vida cambia su estado al despacharse une evento.
Es decir, ajustan su comportamiento en base del ciclo de vida de una actividad o fragmento ya que son conscientes del mismo.
¿Qué ventajas tiene crear estos componentes?
Evitan poner acciones de los componentes y/o librerías dependientes en los controladores del ciclo de vida (ej: onResume()
, onPause()
, onStop()
, etc.) de actividades y fragmentos.
Este aislamiento ayuda a crear código liviano conciso y organizado, lo que se traduce en mayor facilidad de mantenimiento de la app.
¿Qué herramienta usar?
El modelo de observación propuesto en Android Jetpack para componentes conscientes de ciclos de vida de la librería androix.lifecycle.
Básicamente, debemos:
- Implementar la escucha
LifecycleOwner
sobre el componente que tiene el ciclo de vida - Implementar
LifecycleObserver
sobre el componente que realizará acciones basado en el dueño del ciclo de vida - Vincular ambos objetos con
addListener()
La siguiente ilustración muestra la relación entre los componentes de la librería.
Sabiendo esto, sigue leyendo para familiarizarte con las clases.
La Clase Lifecycle
Define a los objetos que tienen un ciclo de vida en Android junto a su información de estados y eventos.
Sus enumeraciones Event
y State
permiten rastrear los flujos posibles del ciclo de vida como se ve la siguiente gráfica:
Event
Denota a los eventos despachados por el framework y Lifecycle
. En actividades y fragmentos estos eventos son el mapeo de los controladores del ciclo de vida.
ON_CREATE
: representa a el evento onCreate del dueño del cicloON_START
: representa a onStartON_RESUME
: representa a onResumeON_PAUSE
: representa a onPauseON_STOP
: representa a onStopON_DESTROY
: representa a onDestroyON_ANY
: constante usada para coincidir con todos los eventos
State
Es el estado actual del componente rastreado por Lifecycle
. Como vimos en el diagrama se compone de:
DESTROYED
: dueño del ciclo destruido. El ciclo de vida no despachará más eventos.INITIALIZED
: dueño construido en memoria, pero aún no ha recibido a onCreate.CREATED
: dueño creado. Se alcanza al llamar a onCreate o antes de llamar a onStopSTARTED
: dueño iniciado. Se alcanza luego de llamar a onStart o antes de llamar a onPauseRESUMED
: dueño resumido. Se alcanza luego de llamar a onResume.
Observador Del Ciclo De Vida
La interfaz LifecycleObserver
representa al observador encargado de monitorear el estado del ciclo de vida de un componente a través de la anotación @OnLifecycleEvent
.
Implementa esta interfaz en tu clase observadora y escribe los manejadores de cada evento que desees trackear:
public class MyLifecycleObserver implements LifecycleObserver { private final Lifecycle mLifecycle; public MyLifecycleObserver(Lifecycle lifecycle) { mLifecycle = lifecycle; mLifecycle.addObserver(this); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void stopHandler() { } }
Usa el método addObserver()
para vincular el dueño del ciclo a tu observador .
Propietario Del Ciclo De Vida
El componente con el ciclo de vida se representa con la interfaz LifecycleOwner
. Su único método getLifecycle()
permite a los observadores estar al tanto del ciclo de vida.
Tanto AppCompatActivity
como Fragment
ya vienen con esta interfaz implementada, por lo que no debes preocuparte de hacerlo.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyLifecycleObserver observer = new MyLifecycleObserver(getLifecycle()); }
Ejemplo De Lifecycle-aware Component
Para experimentar el patrón de observación del ciclo de vida crearemos un nuevo proyecto Android con una actividad vacía.
La idea es imprimir en el logcat el momento en que la actividad pasa por sus métodos de ciclo de vida y como un observador le sigue el paso.
La ejecución sería así…
Definir Dependencias Gradle
El primer paso es incluir las dependencias para ciclos de vida de la siguiente forma:
dependencies { // ... // Lifecycle implementation "androidx.lifecycle:lifecycle-runtime:$lifecycleVersion" annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion" }
La versión del paquete lifecycle puedes aislarla en build.gradle del proyecto así:
ext { appCompatVersion = '1.1.0' constraintLayoutVersion = '1.1.3' espressoVersion = '3.2.0' junitVersion = '4.12' junitAndroidVersion = '1.1.1' lifecycleVersion = '2.2.0' }
Crear Observador Mientras La App Es Visible
Supongamos que deseamos rastrear los métodos onStart()
, onResume()
y onPause()
de la actividad del ejemplo.
Con ese fin en mente, crearemos un observador llamado MainObserver
y agregaremos 3 manejadores con las anotaciones respectivas. En cada uno loguearemos el nombre del evento del ciclo de vida.
publpublic class MainObserver implements LifecycleObserver { private static final String TAG = MainObserver.class.getSimpleName(); private final Lifecycle mLifecycle; public MainObserver(Lifecycle lifecycle) { mLifecycle = lifecycle; // Añadir observador de ciclo de vida lifecycle.addObserver(this); } @OnLifecycleEvent(Lifecycle.Event.ON_START) public void startAction() { Log.d(TAG, "ON_START"); } @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void resumeAction() { Log.d(TAG, "ON_RESUME"); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void pauseAction() { Log.d(TAG, "ON_PAUSE"); } }
Al ejecutar el proyecto Android Studio se loguearán estas líneas:
Y si rotas el dispositivo, verás:
Como ves, el evento onPause del observador es ejecutado primero para realizar las acciones pertinentes ante el comienzo del desmantelamiento de la actividad.
Crear Observador Para Todos Los Eventos
Usaremos el evento Event.ON_ANY
para loguear todos los estados transitados de la actividad.
Basados en ello, creamos la clase AnyObserver
:
public class AnyObserver implements LifecycleObserver {
private static final String TAG = AnyObserver.class.getSimpleName();
private final Lifecycle mLifecycle;
private final Callback mCallback;
public AnyObserver(Lifecycle lifecycle, Callback callback) {
mLifecycle = lifecycle;
mLifecycle.addObserver(this);
mCallback = callback;
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void anyAction() {
String state = mLifecycle.getCurrentState().name();
Log.d(TAG, state);
if (mLifecycle.getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
mCallback.onOwnerResumed(new Date().toString());
}
}
interface Callback{
void onOwnerResumed(String date);
}
}
Este observador usa la interfaz Callback
con el fin de comunicar a la actividad el texto que se asignará al view.
Como ves, anyAction()
loguea el nombre del estado actual (getCurrentState()
). Luego verifica con el método isAtLeast()
si la actividad es visible para el usuario (que el estado actual sea State.RESUMED
).
De ser así, ejecutamos el método onOwnerResumed()
de la callback con la fecha actual.
Si revisas el Logcat verás como transiciona entre todos sus estados.
Añadir Observadores A La Actividad
Finalmente creamos las instancias de los observadores en onCreate()
de la actividad y logueamos todos los métodos del ciclo para el seguimiento:
public class MainActivity extends AppCompatActivity { private static final String TAG = "Lifecycle Owner"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate()"); MainObserver observer = new MainObserver(getLifecycle()); AnyObserver anyObserver = new AnyObserver(getLifecycle(), new AnyObserver.Callback() { @Override public void onOwnerResumed(String date) { TextView textView = findViewById(R.id.text); textView.setText(date); } }); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart()"); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume()"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause()"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy()"); } }
Creamos una instancia anónima para la callback de AnyObserver
, buscamos la referencia del view y asignamos el valor obtenido.
Descargar Código
Descarga el proyecto completo en Android Studio presionando el siguiente botón: