Lifecycle-aware Components De AndroidX

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:

  1. Implementar la escucha LifecycleOwner sobre el componente que tiene el ciclo de vida
  2. Implementar LifecycleObserver sobre el componente que realizará acciones basado en el dueño del ciclo de vida
  3. Vincular ambos objetos con addListener()

La siguiente ilustración muestra la relación entre los componentes de la librería.

Diagrama de clases para hacer seguimiento al ciclo de vida

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 ciclo
  • ON_START: representa a onStart
  • ON_RESUME: representa a onResume
  • ON_PAUSE: representa a onPause
  • ON_STOP: representa a onStop
  • ON_DESTROY: representa a onDestroy
  • ON_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 onStop
  • STARTED: dueño iniciado. Se alcanza luego de llamar a onStart o antes de llamar a onPause
  • RESUMED: 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.

Ejemplo Lifecycle-aware components

Si revisas el Logcat verás como transiciona entre todos sus estados.

Ejemplo de Lifecycle.getCurrentState()

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:

[sociallocker id=»7121″]Descargar Gratis[/sociallocker]

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!