Aspectos básicos de Android Kotlin 04.1: Ciclos de vida y registro

Este codelab es parte del curso Conceptos básicos de Kotlin para Android. Aprovecharás al máximo este curso si trabajas con los codelabs en secuencia. Todos los codelabs del curso se detallan en la página de destino de codelabs sobre los aspectos básicos de Kotlin para Android.

Introducción

En este codelab, aprenderás sobre una parte fundamental de Android: el ciclo de vida de la actividad y el fragmento. El ciclo de vida de la actividad es el conjunto de estados en los que puede estar una actividad durante su ciclo de vida. El ciclo de vida abarca desde el momento en que se crea inicialmente la actividad hasta que esta se destruye y el sistema recupera los recursos de esa actividad. A medida que un usuario navega entre las actividades de tu app (y también cuando ingresa a la app y sale de ella), cada una de esas actividades experimenta una transición entre diferentes estados de su ciclo de vida.

El ciclo de vida del fragmento es muy similar al de las actividades. Este codelab se enfoca principalmente en actividades y ofrece una vista rápida de los fragmentos hacia el final.

Como desarrollador de Android, debes comprender el ciclo de vida de la actividad. Si las actividades no responden correctamente a los cambios de estado del ciclo de vida, es posible que tu app genere errores extraños o comportamientos confusos para los usuarios, o que use demasiados recursos del sistema Android. Comprender el ciclo de vida de Android y responder correctamente a los cambios de estado del ciclo de vida es fundamental para ser un buen ciudadano de Android.

Conocimientos que ya deberías tener

  • Qué es una actividad y cómo crear una en tu app
  • Qué hace el método onCreate() de la actividad y qué tipo de operaciones se realizan en ese método
  • Cómo crear diseños XML para tu actividad y cómo actualizar un diseño durante el tiempo de ejecución

Qué aprenderás

  • Cómo imprimir información de registro en Logcat (a veces llamada Android Console o Android Monitor)
  • Los conceptos básicos de los ciclos de vida Activity y Fragment, y las devoluciones de llamada que se invocan cuando la actividad pasa de un estado a otro
  • La manera de anular métodos de devolución de llamada de ciclo de vida para realizar operaciones en diferentes momentos del ciclo de vida de la actividad
  • Cómo usar la biblioteca Timber para acceder a tu app

Actividades

  • Modifica una app inicial llamada DessertClicker a fin de agregar información de registro que se muestra en Logcat.
  • Anula los métodos de devolución de llamada de ciclo de vida y registra los cambios de estado en el estado de la actividad.
  • Ejecuta la app y observa la información de registro que aparece cuando se inicia, se detiene y se reanuda la actividad.
  • Modifica la app para usar la biblioteca Timber.
  • Agrega registros a la app de AndroidTrivia y supervisa los cambios en los estados de fragmentos.

En este codelab, trabajarás con una app inicial llamada DessertClicker. En esta app, cada vez que el usuario presiona un postre en la pantalla, la app "compra" el postre para el usuario. La app actualiza los valores en el diseño para la cantidad de postres que se compraron y el importe total que el usuario gastó.

Esta app contiene varios errores relacionados con el ciclo de vida de Android. Por ejemplo, en determinadas circunstancias, la app restablece los valores de los postres a 0 y continúa usando recursos del sistema incluso cuando está en segundo plano. Comprender el ciclo de vida de Android te ayudará a comprender por qué ocurren estos problemas y cómo corregirlos.

Cada actividad y cada fragmento tienen lo que se conoce como un ciclo de vida. Esta es una alusión a los ciclos de vida de los animales, como el ciclo de vida de esta mariposa. Los diferentes estados de la mariposa muestran su crecimiento desde que nace hasta que se convierte en un adulto pleno y, luego, hasta que muere.

De manera similar, el ciclo de vida de la actividad se compone de los diferentes estados que puede atravesar una actividad, por ejemplo, cuando se inicializa por primera vez hasta que al final se destruye y el sistema recupera su memoria. Cuando el usuario inicia tu app y navega dentro y fuera de ella, y entre las actividades, la actividad cambia de estado. En el siguiente diagrama, se muestran todos los estados del ciclo de vida de las actividades. Como los nombres lo indican, estos estados representan el estado de la actividad.

A menudo, quieres cambiar algún comportamiento o ejecutar algún código cuando cambia el estado del ciclo de vida de la actividad. Por lo tanto, la clase Activity en sí misma y cualquier subclase de Activity, como AppCompatActivity, implementan un conjunto de métodos de devolución de llamada de ciclo de vida. Android invoca estas devoluciones de llamada cuando la actividad pasa de un estado a otro, y puedes anular esos métodos en tus propias actividades a fin de realizar tareas en respuesta a esos cambios de estado del ciclo de vida. En el siguiente diagrama, se muestran los estados del ciclo de vida junto con las devoluciones de llamada anulables disponibles.

Un fragmento también tiene un ciclo de vida. El ciclo de vida de un fragmento es similar al de una actividad, por lo que mucho de lo que aprenderás se aplica a ambos. En este codelab, te concentrarás en el ciclo de vida de la actividad porque es una parte fundamental de Android y la más fácil de observar en una app simple. A continuación, verás el diagrama correspondiente al ciclo de vida del fragmento:

Es importante saber cuándo se invocan estas devoluciones de llamada y qué hacer en cada método de devolución de llamada. Sin embargo, ambos diagramas son complejos y pueden ser confusos. En este codelab, en lugar de solo leer lo que significa cada estado y devolución de llamada, investigarás y desarrollarás tus ideas sobre lo que está sucediendo.

Paso 1: Observa el método onCreate() y agrega registros

Para determinar lo que sucede con el ciclo de vida de Android, es útil saber cuándo se llama a los diferentes métodos de ciclo de vida. Esto te ayudará a identificar problemas en DessertClicker.

Una manera sencilla de hacerlo es usar la API de registro de Android. El registro te permite escribir mensajes cortos en una consola mientras la app se ejecuta, y puedes usarlo para que te muestre cuándo se activan las diferentes devoluciones de llamada.

  1. Descarga la app de inicio de DessertClicker y ábrela en Android Studio.
  2. Compila y ejecuta la app, y presiona varias veces la imagen del postre. Observa cómo cambia el valor de Postres vendidos y el importe total en dólares.
  3. Abre MainActivity.kt y examina el método onCreate() para esta actividad
override fun onCreate(savedInstanceState: Bundle?) {
...
}

En el diagrama del ciclo de vida de la actividad, es posible que hayas reconocido el método onCreate(), dado que ya usaste esta devolución de llamada con anterioridad. Este es el único método que deben implementar todas las actividades. El método onCreate() es aquel en el cual debes realizar las inicializaciones únicas para tu actividad. Por ejemplo, en onCreate(), se aumenta el diseño, se definen objetos de escucha de clics o se configura la vinculación de datos.

Se llama al método de ciclo de vida de onCreate() una vez, justo después de que se inicializa la actividad (cuando se crea el nuevo objeto Activity en la memoria). Después de que se ejecuta onCreate(), la actividad se considera creada.

  1. En el método onCreate(), justo después de la llamada a super.onCreate(), agrega la siguiente línea: Importa la clase Log si es necesario. (Presiona Alt+Enter o Option+Enter en Mac y selecciona Import).
Log.i("MainActivity", "onCreate Called")

La clase Log escribe mensajes en Logcat. Este comando tiene tres partes:

  • La gravedad del mensaje de registro, es decir, cuán importante es el mensaje. En este caso, el método Log.i() escribe un mensaje informativo. Otros métodos de la clase Log incluyen Log.e() para errores, o Log.w() para advertencias.
  • La etiqueta del registro, en este caso, "MainActivity". La etiqueta es una string que te permite encontrar con mayor facilidad los mensajes de registro en Logcat. La etiqueta suele ser el nombre de la clase.
  • El mensaje de registro real, una string corta, que en este caso es "onCreate called".
  1. Compila y ejecuta la app DessertClicker. No verás ninguna diferencia de comportamiento en la app cuando presiones el postre. En Android Studio, en la parte inferior de la pantalla, haz clic en la pestaña Logcat.



    El Logcat es la consola para registrar mensajes. Aquí aparecen los mensajes de Android sobre tu app, incluidos los mensajes que envías de manera explícita al registro con el método Log.i() u otros métodos de clase Log.
  2. En el panel Logcat, escribe I/MainActivity en el campo de búsqueda.


    El elemento Logcat puede contener muchos mensajes, y la mayoría no es útil. Puedes filtrar las entradas de Logcat de muchas maneras, pero es más sencillo realizar una búsqueda. Dado que usaste MainActivity como la etiqueta de registro en tu código, puedes usar esa etiqueta a fin de filtrar el registro. Agregar I/ al principio significa que se trata de un mensaje informativo, que creó Log.i().

    Tu mensaje incluye la fecha y hora, el nombre del paquete (com.example.android.dessertclicker), tu etiqueta de registro (con I/ al inicio) y el mensaje en sí. Como este mensaje aparece en el registro, sabes que se ejecutó onCreate().

Paso 2: Implementa el método onStart()

Se llama al método de ciclo de vida de onStart() justo después de onCreate(). Una vez que se ejecute onStart(), tu actividad se visualizará en la pantalla. A diferencia de lo que ocurre con onCreate(), que se llama solo una vez para inicializar tu actividad, se puede llamar a onStart() muchas veces durante el ciclo de vida de tu actividad.

Ten en cuenta que onStart() está vinculado con el método de ciclo de vida onStop() correspondiente. Si el usuario inicia tu app y luego regresa a la pantalla principal del dispositivo, la actividad se detendrá y ya no estará visible en la pantalla.

  1. En Android Studio, con MainActivity.kt abierto, selecciona Code > Override Methods o presiona Control+o. Aparecerá un diálogo con una lista enorme de todos los métodos que puedes anular en esta clase.
  2. Comienza a ingresar onStart para buscar el método adecuado. Para desplazarte al siguiente elemento coincidente, usa la flecha hacia abajo. Selecciona onStart() de la lista y haz clic en OK para insertar el código estándar de anulación. El código se ve así:
override fun onStart() {
   super.onStart()
}
  1. Dentro del método onStart(), agrega un mensaje de registro:
override fun onStart() {
   super.onStart()

   Log.i("MainActivity", "onStart Called")
}
  1. Compila y ejecuta la app DessertClicker, y abre el panel de Logcat. Escribe I/MainActivity en el campo de búsqueda para filtrar el registro. Ten en cuenta que los métodos onCreate() y onStart() se llamaron uno tras otro y que tu actividad se visualiza en pantalla.
  2. Presiona el botón de inicio del dispositivo y luego usa la pantalla Recientes para volver a la actividad. Ten en cuenta que la actividad se reanudará donde la dejaste, con los mismos valores, y que onStart() se registrará por segunda vez en Logcat. Observa también que no se suele volver a llamar al método onCreate().

En esta tarea, modificarás la app para que use una biblioteca de registros popular llamada Timber. Timber tiene varias ventajas sobre la clase Log integrada de Android. En particular, la biblioteca Timber:

  • Genera la etiqueta de registro por usted según el nombre de la clase.
  • Ayuda a evitar que se muestren registros en una versión de actualización de tu app para Android.
  • Permite la integración con bibliotecas de informes de fallas.

Verás el primer beneficio de inmediato; las demás apps que apreciarás a medida que las crees y publiques.

Paso 1: Agrega madera a Gradle

  1. Visita este vínculo para ir al proyecto Timmber en GitHub y copia la línea de código debajo del encabezado Download que comienza con la palabra implementation. La línea de código se verá de la siguiente manera, aunque el número de versión puede ser diferente.
implementation 'com.jakewharton.timber:timber:4.7.1'
  1. En Android Studio, en la vista Proyecto: Android, expande Gradle Scripts y abre el archivo build.gradle (Module: app).
  2. Dentro de la sección de dependencias, pega la línea de código que copiaste.
dependencies {
   ...
   implementation 'com.jakewharton.timber:timber:4.7.1'
}
  1. Para volver a compilar Gradle, haz clic en el vínculo Sync Now ubicado en la parte superior derecha de Android Studio. La compilación debería ejecutarse sin errores.

Paso 2: Crea una clase Application e inicializa Timber

En este paso, crearás una clase Application. Application es una clase base que contiene el estado de la aplicación global para toda la app. También es el objeto principal que usa el sistema operativo para interactuar con la app. Existe una clase Application predeterminada que Android usa si no especificas una, de manera que siempre se crea un objeto Application para tu app, sin necesidad de que hagas nada especial para crearla.

Timber usa la clase Application porque toda la app usará esta biblioteca de registro, y la biblioteca se debe inicializar una vez, antes de que todo lo demás se configure. En casos como este, puedes subclasificar la clase Application y anular los valores predeterminados con tu propia implementación personalizada.

Después de crear tu clase Application, debes especificarla en el manifiesto de Android.

  1. En el paquete dessertclicker, crea una nueva clase de Kotlin llamada ClickerApplication. Para ello, expande app > java y haz clic con el botón derecho en com.example.android.dessertclicker. Selecciona New > Kotlin File/Class.
  2. Asígnele el nombre ClickerApplication a la clase y establezca el Tipo en Clase. Haz clic en OK.

Android Studio creará una nueva clase de ClickerApplication y la abrirá en el editor de código. El código se ve así:

package com.example.android.dessertclicker

class ClickerApplication {
}
  1. Cambia la definición de clase para que sea una subclase de Application y, si es necesario, importa la clase Application.
class ClickerApplication : Application() {
  1. Para anular el método onCreate(), selecciona Code > Override Methods o presiona Control+o.
class ClickerApplication : Application() {
   override fun onCreate() {
       super.onCreate()
   }
}
  1. Dentro de ese método onCreate(), inicializa la biblioteca Timber:
override fun onCreate() {
    super.onCreate()

    Timber.plant(Timber.DebugTree())
}

Esta línea de código inicializa la biblioteca Timber de tu app para que puedas usarla en tus actividades.

  1. Abre AndroidManifest.xml.
  2. En la parte superior del elemento <application>, agrega un nuevo atributo para la clase ClickerApplication, de modo que Android sepa usar tu clase Application en lugar de la predeterminada.
<application
   android:name=".ClickerApplication"
...

Paso 3: Agrega instrucciones de registro de madera

En este paso, cambiarás las llamadas a Log.i() para usar Timber y, luego, implementarás el registro de todos los demás métodos del ciclo de vida.

  1. Abre MainActivity y desplázate hasta onCreate(). Reemplaza Log.i() por Timber.i() y quita la etiqueta de registro.
Timber.i("onCreate called")

Al igual que la clase Log, Timber también usa el método i() para mensajes informativos. Ten en cuenta que, con Timber, no necesitas agregar una etiqueta de registro; Timber usa automáticamente el nombre de la clase como la etiqueta de registro.

  1. De manera similar, cambia la llamada a Log en onStart():
override fun onStart() {
   super.onStart()

   Timber.i("onStart Called")
}
  1. Compila y ejecuta la app DessertClicker, y abre Logcat. Observa que aún ves los mismos mensajes de registro para onCreate() y onStart(), solo que ahora Timber genera esos mensajes, no la clase Log.
  2. Anula el resto de los métodos del ciclo de vida de tu MainActivity y agrega instrucciones de registro Timber para cada uno. Este es el código:
override fun onResume() {
   super.onResume()
   Timber.i("onResume Called")
}

override fun onPause() {
   super.onPause()
   Timber.i("onPause Called")
}

override fun onStop() {
   super.onStop()
   Timber.i("onStop Called")
}

override fun onDestroy() {
   super.onDestroy()
   Timber.i("onDestroy Called")
}

override fun onRestart() {
   super.onRestart()
   Timber.i("onRestart Called")
}
  1. Vuelve a compilar y ejecutar DessertClicker, y revisa Logcat. Esta vez, observa que, además de onCreate() y onStart(), hay un mensaje de registro para la devolución de llamada de ciclo de vida onResume().

Cuando una actividad se inicie desde cero, verás las tres devoluciones de llamada de ciclo de vida llamadas en orden:

  • onCreate() para crear la app
  • onStart() para iniciarla y hacerla visible en la pantalla
  • onResume() para poner atención en la actividad y prepararla de modo que el usuario interactúe con ella

A pesar de su nombre, se llama al método onResume() durante el inicio, incluso si no hay nada para reanudar.

Ahora que la app DessertClicker está configurada para el registro, está todo listo para comenzar a usar la app de varias maneras y puedes explorar la forma en que se activan las devoluciones de llamada de ciclo de vida en respuesta a esos usos.

Caso de uso 1: Cómo abrir y cerrar la actividad

Comenzarás con el caso de uso más básico, que es iniciar tu app por primera vez y luego cerrarla por completo.

  1. Compila y ejecuta la app DessertClicker si aún no se está ejecutando. Como ya viste, se llama a las devoluciones de llamada onCreate(), onStart() y onResume() cuando la actividad se inicia por primera vez.
  2. Presiona el pastelito algunas veces.
  3. Presiona el botón Atrás en el dispositivo. En Logcat, observa que se llama a onPause(), onStop() y onDestroy() en ese orden.

    En este caso, usar el botón Atrás causa que la actividad (y la app) se cierre por completo. La ejecución del método onDestroy() significa que la actividad se cerró por completo y puede realizarse la recolección de elementos no utilizados. La recolección de elementos no utilizados se refiere a la limpieza automática de los objetos que ya no usarás. Después de llamar a onDestroy(), el SO sabe que esos recursos se pueden descartar y comienza a limpiar esa memoria.

    Tu actividad también puede cerrarse por completo si tu código llama manualmente al método finish() de la actividad o si el usuario fuerza el cierre de la app (por ejemplo, el usuario puede forzar el cierre de la app en la pantalla Recientes haciendo clic en la X en la esquina de la ventana). El sistema Android también puede cerrar tu actividad por sí solo si tu app no aparece en la pantalla por mucho tiempo. El propósito de este proceso es conservar la batería y permitir que otras apps usen los recursos que utiliza la tuya.
  4. Usa la pantalla Recientes para volver a la app. A continuación, se muestra el registro de Logcat:


    La actividad se destruyó en el paso anterior, por lo que, cuando regresas a la app, Android inicia una actividad nueva y llama a los métodos onCreate(), onStart() y onResume(). Observa que no se retuvo ninguna de las estadísticas de DessertClicker de la actividad anterior.

    El punto clave aquí es que solo se llama a onCreate() y onDestroy() una vez durante el ciclo de vida de una única instancia de actividad: onCreate() para inicializar la app por primera vez y onDestroy() para limpiar los recursos que usa tu app.

    El método onCreate() es un paso importante; aquí es donde se realiza la primera inicialización, donde aumentas el diseño y realizas las variables.

Caso de uso 2: Cómo salir de la actividad y volver a ella

Ahora que iniciaste la app y la cerraste por completo, viste la mayoría de los estados del ciclo de vida para cuando la actividad se crea por primera vez. También conoces todos los estados del ciclo de vida que la actividad atraviesa cuando se cierra y se destruye por completo. Sin embargo, a medida que los usuarios interactúan con sus dispositivos Android, pasan de una app a otra, regresan al inicio, inician apps nuevas y manejan interrupciones provocadas por otras actividades (por ejemplo, llamadas telefónicas).

Tu actividad no se cierra por completo cada vez que el usuario sale de la actividad:

  • Cuando tu actividad ya no está visible en la pantalla, se habla de que se colocó la actividad en segundo plano. (Lo contrario de esto es cuando la actividad está en primer plano o en pantalla).
  • Cuando el usuario regresa a tu app, se reinicia la misma actividad y la app vuelve a estar visible. Esta parte del ciclo de vida se denomina ciclo de vida visible de la app.

Cuando la app está en segundo plano, no debe ejecutarse de forma activa para conservar los recursos del sistema y la duración de la batería. Puedes usar el ciclo de vida de Activity y sus devoluciones de llamada para saber en qué momento tu app pasa a segundo plano de modo que puedas pausar las operaciones en curso. Luego, reinicia las operaciones cuando tu app pase a primer plano.

Por ejemplo, piensa en una app que ejecuta una simulación física. Se necesitan muchos cálculos, calculados en la CPU de tu dispositivo, para decidir dónde deben estar todos los objetos de la simulación y mostrarlos. Si una llamada telefónica interrumpe la simulación, el usuario podría confundirse o incluso molestarse para volver a la app y ver que la simulación haya finalizado.

Esto también se debe a las razones de rendimiento. Supongamos que el usuario abrió 20 apps que usan simulaciones físicas de uso intensivo de CPU. Si esas actividades no aparecen en pantalla, pero siguen realizando cálculos de renderización en segundo plano, ralentizará el rendimiento de todo el teléfono.

En este paso, observas el ciclo de vida de la actividad cuando la app pasa a segundo plano y vuelve a primer plano.

  1. Con la app DessertClicker en ejecución, haz clic varias veces en el pastelito.
  2. Presiona el botón de inicio de tu dispositivo y observa Logcat en Android Studio. Cuando regresas a la pantalla principal, tu aplicación se ejecuta en segundo plano en lugar de cerrarse por completo. Observa que se llama a los métodos onPause() y onStop(), pero no a onDestroy().


    Cuando se llama a onPause(), la app ya no tiene foco. Después de onStop(), la app deja de estar visible en la pantalla. Aunque la actividad se detuvo, el objeto Activity todavía está en la memoria, en segundo plano. No se destruyó la actividad. El usuario podría regresar a la app, por lo que Android conserva los recursos de la actividad.
  3. Usa la pantalla Recientes para volver a la app. Observa que en Logcat la actividad se reinicia con onRestart() y onStart(), y luego se reanuda con onResume().


    Cuando la actividad vuelve a primer plano, no se vuelve a llamar al método onCreate(). No se destruyó el objeto de la actividad, por lo que no es necesario volver a crearlo. En lugar de onCreate(), se llama al método onRestart(). Ten en cuenta que esta vez, cuando la actividad regrese a primer plano, se conservará la cantidad de Postres vendidos.
  4. Inicia al menos una app que no sea DessertClicker de modo que el dispositivo tenga algunas apps en su pantalla Recientes.
  5. Abre la pantalla Recientes y abre otra actividad reciente. Luego, regresa a las apps recientes y vuelve a poner DessertClicker en primer plano.

    Observa que ves las mismas devoluciones de llamada en Logcat aquí que cuando presionaste el botón de inicio. Se llama a onPause() y onStop() cuando la app pasa a segundo plano y, luego, a onRestart(), onStart() y onResume() cuando regresa.

    El punto importante aquí es que se llama a onStart() y onStop() varias veces a medida que el usuario navega hacia la actividad y desde ella. Deberías anular estos métodos para detener la app cuando pase a segundo plano o volver a iniciarla cuando regrese a primer plano.

    ¿Qué ocurre con onRestart()? El método onRestart() es muy similar a onCreate(). Se llama a onCreate() o onRestart() antes de que se muestre la actividad. Se llama al método onCreate() solo la primera vez. Luego, se llama a onRestart(). El método onRestart() es un lugar para colocar código que quieras llamar solamente si la actividad no se inicia por primera vez.

Caso de uso 3: Cómo ocultar parcialmente la actividad

Ya vimos que, cuando se inicia una app y se llama a onStart(), la app se hace visible en la pantalla. Cuando se reanuda la app y se llama a onResume(), la app atrae la atención del usuario. La parte del ciclo de vida en la que la app se muestra en pantalla y tiene la atención del usuario se denomina ciclo de vida interactivo.

Cuando la app pasa a segundo plano, el foco de atención se pierde después de onPause(), y la app deja de ser visible después de onStop().

La diferencia entre el foco de atención y la visibilidad es importante porque es posible que una actividad sea parcialmente visible en pantalla, pero no tenga la atención del usuario. En este paso, verás un caso de este tipo.

  1. Con la app DessertClicker en ejecución, haz clic en el botón Share, en la parte superior derecha de la pantalla.




    La actividad de la función compartir aparece en la mitad inferior de la pantalla, pero la actividad aún está visible en la mitad superior.
  2. Revisa Logcat y observa que solo se llamó a onPause().


    En este caso de uso, no se llama a onStop() porque la actividad aún está parcialmente visible. Sin embargo, la actividad no tiene la atención del usuario, y el usuario no puede interactuar con ella. La actividad "compartir" que está en primer plano tiene el enfoque del usuario.

    ¿Por qué esta diferencia es importante? Ten en cuenta la app de física. Es posible que quieras que la simulación se detenga cuando la app está en segundo plano y que se siga ejecutando cuando esté parcialmente oculta. En este caso, detenerías la simulación en onStop(). Si deseas que la simulación se detenga cuando la actividad se oculta parcialmente, debes colocar el código para detener la simulación en onPause().

    El código que se ejecute en onPause() bloqueará otras cosas, por lo que debes mantener un código liviano en onPause(). Por ejemplo, si llega una llamada telefónica, el código de onPause() podría retrasar la notificación de llamada entrante.
  3. Haz clic fuera del cuadro de diálogo de la función compartir para volver a la app y observa que se llama a onResume().

    Tanto onResume() como onPause() están relacionados con el foco. Se llama al método onResume() cuando la actividad tiene el foco, y se llama a onPause() cuando esta lo pierde.

El ciclo de vida de los fragmentos de Android es similar al de una actividad, además de varios métodos específicos de cada fragmento.

En esta tarea, observarás la app de AndroidTrivia que creaste en codelabs anteriores y agregarás algunos registros para explorar el ciclo de vida del fragmento. La aplicación AndroidTrivia te permite responder preguntas sobre el desarrollo de Android; si respondes tres preguntas seguidas correctamente, ganas el juego.

Cada pantalla de la app de AndroidTrivia es un Fragment.

Para simplificar el proceso, en esta tarea, usarás la API de Logging para Android en lugar de la biblioteca Timber.

  1. Abre la app de AndroidTrivia del último codelab o descarga el código de la solución AndroidTrivia en GitHub.
  2. Abre el archivo TitleFragment.kt. Ten en cuenta que Android Studio podría mostrar errores de vinculación y errores de referencia no resueltos hasta que vuelvas a compilar la app.
  3. Desplázate hacia abajo hasta el método onCreateView(). Observa que aquí es donde se aumenta el diseño del fragmento y se produce la vinculación de datos.
  4. Agrega una instrucción de registro al método onCreateView(), entre la línea a setHasOptionsMenu() y la llamada final que se mostrará:
setHasOptionsMenu(true)

Log.i("TitleFragment", "onCreateView called")

return binding.root
  1. Debajo del método onCreateView(), agrega instrucciones de registro para cada uno de los métodos restantes del ciclo de vida del fragmento. Este es el código:
override fun onAttach(context: Context?) {
   super.onAttach(context)
   Log.i("TitleFragment", "onAttach called")
}
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   Log.i("TitleFragment", "onCreate called")
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
   super.onActivityCreated(savedInstanceState)
   Log.i("TitleFragment", "onActivityCreated called")
}
override fun onStart() {
   super.onStart()
   Log.i("TitleFragment", "onStart called")
}
override fun onResume() {
   super.onResume()
   Log.i("TitleFragment", "onResume called")
}
override fun onPause() {
   super.onPause()
   Log.i("TitleFragment", "onPause called")
}
override fun onStop() {
   super.onStop()
   Log.i("TitleFragment", "onStop called")
}
override fun onDestroyView() {
   super.onDestroyView()
   Log.i("TitleFragment", "onDestroyView called")
}
override fun onDetach() {
   super.onDetach()
   Log.i("TitleFragment", "onDetach called")
}
  1. Compila y ejecuta la app, y abre Logcat.
  2. Escribe I/TitleFragment en el campo de búsqueda para filtrar el registro. Cuando se inicie la app, Logcat se verá como la siguiente captura de pantalla:

Aquí puedes ver todo el ciclo de vida de inicio del fragmento, incluidas estas devoluciones de llamada:

  • onAttach(): Se llama cuando el fragmento se asocia con su actividad de propietario.
  • onCreate(): De manera similar a onCreate() para la actividad, se llama a onCreate() para el fragmento a fin de crear el fragmento inicial (aparte del diseño).
  • onCreateView(): Se llama para aumentar el diseño del fragmento.
  • onActivityCreated(): Se llama cuando se completa la actividad del propietario onCreate(). Tu fragmento no podrá acceder a la actividad hasta que se llame a este método.
  • onStart(): Se llama cuando se hace visible el fragmento; paralelo a onStart() de la actividad.
  • onResume(): Se llama cuando el fragmento obtiene el enfoque del usuario; paralelo a la onResume() de la actividad.
  1. Presiona el botón Jugar para continuar con el juego de preguntas y respuestas y observa el Logcat ahora.

Cuando se abre el siguiente fragmento, el fragmento de título se cierra y se llama a estos métodos del ciclo de vida:

  • onPause(): Se llama cuando el fragmento pierde el foco del usuario; paralelo al onPause() de la actividad.
  • onStop(): Se llama cuando el fragmento ya no está visible en la pantalla; es paralelo al objeto onStop() de la actividad.
  • onDestroyView(): Se llama cuando ya no se necesita la vista de fragmento para limpiar los recursos asociados con esa vista.
  1. En la app, presiona el botón Arriba (la flecha que aparece en la esquina superior izquierda de la pantalla) para volver al fragmento de título.


    Es posible que no se llame a onAttach() y onCreate() para iniciar el fragmento. El objeto del fragmento aún existe y se adjunta a su actividad de propietario, por lo que el ciclo de vida comienza nuevamente con onCreateView().
  2. Presiona el botón de inicio del dispositivo. En Logcat, observa que solo se llama a onPause() y onStop(). Este es el mismo comportamiento que en la actividad: cuando vuelves a casa, la actividad y el fragmento pasan a segundo plano.
  3. Usa la pantalla Recientes para volver a la app. Al igual que con la actividad, se llama a los métodos onStart() y onResume() para mostrar el fragmento en primer plano.

Proyecto de Android Studio: DessertClickerLogs

Ciclo de vida de la actividad

  • El ciclo de vida de la actividad es un conjunto de estados a través de los cuales migra una actividad. El ciclo de vida de la actividad comienza cuando se crea la actividad por primera vez y finaliza cuando esta se destruye.
  • A medida que el usuario navega entre las actividades de tu app (y también cuando ingresa a la app y sale de ella), cada actividad cambia entre diferentes estados del ciclo de vida de la actividad.
  • Cada estado del ciclo de vida de la actividad tiene un método de devolución de llamada correspondiente que puedes anular en tu clase Activity. Existen siete métodos de ciclo de vida:
    onCreate()
    onStart()
    onPause()
    onRestart()
    onResume()
    onStop()
    onDestroy()
  • Para agregar un comportamiento que ocurra cuando tu actividad pase a un estado del ciclo de vida, anula el método de devolución de llamada del estado.
  • Para agregar el esqueleto de métodos de anulación a tus clases en Android Studio, selecciona Code > Override Methods o presiona Control+o.

Realiza un registro con Log

  • La API de Logging de Android y, en particular, la clase Log te permiten escribir mensajes cortos que se muestran en Logcat dentro de Android Studio.
  • Usa Log.i() para escribir un mensaje informativo. Este método usa dos argumentos: la etiqueta de registro (en general, el nombre de la clase) y el mensaje de registro (una string corta).
  • Usa el panel Logcat de Android Studio a fin de ver los registros del sistema, incluidos los mensajes que escribas.

Registro con Timber

Timber es una biblioteca de registro con varias ventajas sobre la API de registro de Android. En particular, la biblioteca Timber:

  • Genera la etiqueta de registro por usted según el nombre de la clase.
  • Ayuda a evitar que se muestren los registros en una versión de actualización de tu app para Android.
  • Permite la integración con bibliotecas de informes de fallas.

Para usar Timber, agrega su dependencia al archivo de Gradle y extiende la clase Application a fin de inicializarla:

  • Application es una clase base que contiene el estado de la aplicación para toda tu app. Existe una clase predeterminada Application que Android usa si no especificas una. Puedes crear tu propia subclase de Application para inicializar bibliotecas de toda la app, como Timber.
  • Para agregar tu clase Application personalizada a tu app, agrega el atributo android:name al elemento <application> en el manifiesto de Android. ¡No lo olvides!
  • Usa Timber.i() para escribir mensajes de registro con Timber. Este método solo admite un argumento: el mensaje que se escribe. La etiqueta de registro (el nombre de la clase) se agrega automáticamente.

Curso de Udacity:

Documentación para desarrolladores de Android:

Otro:

En esta sección, se enumeran las posibles tareas para los alumnos que trabajan con este codelab como parte de un curso que dicta un instructor. Depende del instructor hacer lo siguiente:

  • Si es necesario, asigna la tarea.
  • Informa a los alumnos cómo enviar los deberes.
  • Califica las tareas.

Los instructores pueden usar estas sugerencias lo poco o lo que quieran, y deben asignar cualquier otra tarea que consideren apropiada.

Si estás trabajando en este codelab por tu cuenta, usa estas tareas para poner a prueba tus conocimientos.

Cómo cambiar una app

Abre la app de DiceRoller de la Lección 1. (Puedes descargar la app de DiceRoller aquí si no la tienes). Agrega compatibilidad con Timber a esa app, con el mismo proceso que realizaste para la app DessertClicker. Anula todas las devoluciones de llamada de ciclo de vida y agrega mensajes de registro para cada devolución de llamada.

Responda estas preguntas

Pregunta 1

¿Cuál de las siguientes opciones NO es un estado del ciclo de vida de la actividad?

  • Inicio
  • En espera
  • Creado
  • Destruido

Pregunta 2

¿A qué método de ciclo de vida se llama para que una actividad sea visible?

  • onPause()
  • onVisible()
  • onStart()
  • onDestroy()

Pregunta 3

¿A qué método de ciclo de vida se llama para darle un enfoque a la actividad?

  • onResume()
  • onVisible()
  • onStart()
  • onFocus()

Pregunta 4

¿Cuándo se llama a onCreate() en una actividad?

  • Cada vez que la actividad es visible para el usuario
  • Cada vez que la actividad regresa del fondo
  • Solo una vez, cuando se crea la actividad.
  • Solo una vez, cuando se reanude la actividad.

Envía tu app para que se califique

Asegúrate de que la app tenga lo siguiente:

  • Una dependencia para Timber en el archivo build.gradle de la app
  • Una subclase personalizada de Application que inicializa Timber en onCreate()
  • Un atributo para esa subclase personalizada en el manifiesto de Android.
  • Anulaciones de métodos en MainActivity para todos los métodos de devolución de llamada de ciclo de vida, con llamadas a Timber.i() para el registro

Comienza la siguiente lección: 4.2: Situaciones complejas de ciclo de vida

Para ver vínculos a otros codelabs de este curso, consulta la página de destino de codelabs sobre aspectos básicos de Kotlin para Android.