Lifecycle en Jetpack Compose como parte de Android Jetpack.
Los componentes optimizados para ciclos de vida realizan acciones como respuesta a un cambio en el estado del ciclo de vida de la actividad host. El
androidx.lifecycle.compose
artefacto proporciona APIs dedicadas que limpian automáticamente los recursos cuando
salen de la pantalla o cuando la aplicación pasa a segundo plano.
Entre las APIs clave, se incluyen las siguientes:
- Flujos para el
Lifecycle.Stateactual. LifecycleEffects, que te permite ejecutar un bloque basado en unLifecycle.Eventespecífico
Estas integraciones proporcionan hooks convenientes para administrar ciclos de vida dentro de la jerarquía de Compose. En este documento, se describe cómo puedes usarlas en tu app.
Cómo recopilar el estado del ciclo de vida con flujos
Lifecycle expone una propiedad currentStateFlow que proporciona el Lifecycle.State actual como un StateFlow de Kotlin. Puedes recopilar este Flow como State. De esta forma, se permite que tu app lea los cambios del ciclo de vida durante la composición.
val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow
…
val currentLifecycleState by stateFlow.collectAsState()
Se puede acceder al ejemplo anterior con el módulo lifecycle-common. El método currentStateAsState() está disponible en el módulo lifecycle-runtime-compose, lo que te permite leer de manera conveniente el estado actual del ciclo de vida con una sola línea. En el siguiente ejemplo, se demuestra esto:
val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()
Cómo ejecutar código en eventos de ciclo de vida
En lugar de crear una clase independiente que implemente
DefaultLifecycleObserver
y agregarla manualmente al ciclo de vida, puedes declarar la lógica del ciclo de vida en línea
con efectos específicos. LifecycleEffects te permite ejecutar un bloque cuando se produce un Lifecycle.Event en particular directamente dentro de la composición.
LifecycleEventEffect
Usa LifecycleEventEffect para ejecutar un bloque de código
cuando se produce un evento específico. Esto es mejor para eventos únicos, como el registro o la analítica, en los que no se necesita éxito ni un resultado inmediato.
@Composable
fun AnalyticsTracker(screenName: String) {
// Log an event when the app receives ON_RESUME (e.g. comes to foreground)
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
Analytics.logView(screenName)
}
}
LifecycleStartEffect
Para las operaciones de inicio/detención vinculadas que deben ejecutarse mientras se inicia la app
(visible) y limpiarse cuando se detiene (en segundo plano), usa
LifecycleStartEffect.
Al igual que otros efectos de Compose (como LaunchedEffect), LifecycleStartEffect acepta claves. Cuando la clave cambia, activa el bloque para que vuelva a ejecutarse.
Cuando se produce un evento Lifecycle.Event.ON_STOP o el efecto sale de la composición, ejecuta el bloque onStopOrDispose para limpiar cualquier trabajo que fuera parte del bloque de partida.
@Composable
fun LocationMonitor(locationManager: LocationManager) {
// Starts monitoring when ON_START is dispatched
// Stops monitoring when ON_STOP is dispatched
// (or the composable leaves the screen)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { location ->
/* update UI */
}
locationManager.requestLocationUpdates(listener)
// The cleanup block automatically runs on ON_STOP or on disposal
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
Para obtener información sobre otros tipos de efectos secundarios, consulta Efectos secundarios en Compose.
LifecycleResumeEffect
LifecycleResumeEffect funciona de la misma manera que LifecycleStartEffect, pero está vinculado al evento Lifecycle.Event.ON_RESUME. También proporciona un bloque onPauseOrDispose que realiza la limpieza cuando se envía ON_PAUSE o el elemento componible sale de la pantalla.
Esta API es útil para los recursos que deben estar activos solo cuando el usuario interactúa con la app, por ejemplo, cámaras o animaciones.
@Composable
fun CameraPreview(cameraController: CameraController) {
LifecycleResumeEffect(cameraController) {
cameraController.startPreview()
onPauseOrDispose {
cameraController.stopPreview()
}
}
}
Accede a LifecycleOwner
En Compose, el
LifecycleOwner está
disponible de forma implícita a través de CompositionLocal llamado LocalLifecycleOwner. De forma predeterminada, el host raíz de tu jerarquía de composición proporciona este propietario.
val lifecycleOwner = LocalLifecycleOwner.current
Para muchas apps, es suficiente con inspeccionar este propietario predeterminado o pasarlo a efectos optimizados para ciclos de vida. Sin embargo, para la navegación personalizada o los diseños complejos, es posible que quieras crear tu propio LifecycleOwner para definir los estados del ciclo de vida en secciones específicas de la IU. Por ejemplo, las bibliotecas de navegación (como Navigation
3) lo hacen automáticamente para darle a cada
pantalla individual su propio ciclo de vida.
Crea un LifecycleOwner personalizado
La API de rememberLifecycleOwner() te permite crear y recordar un
personalizadoLifecycleOwner. Esto es especialmente útil para componentes como HorizontalPager, en los que solo quieres que la página visible y establecida sea RESUMED, mientras configuras un maxState de STARTED para las páginas adyacentes fuera de la pantalla.
val pagerState = rememberPagerState(pageCount = { 10 })
HorizontalPager(state = pagerState) { pageNum ->
val pageLifecycleOwner = rememberLifecycleOwner(
maxState = if (pagerState.settledPage == pageNum) {
Lifecycle.State.RESUMED
} else {
Lifecycle.State.STARTED
}
)
CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
// Your pages here. Their lifecycle-aware components respect the
// custom maxState defined above.
}
}
Para obtener más información sobre CompositionLocal, consulta Datos de permisos local con
CompositionLocal.
Prácticas recomendadas para componentes optimizados para ciclos de vida
- Mantén tus controladores de IU tan simples como sea posible. No deberían intentar adquirir sus propios datos. En su lugar, usa un
ViewModela fin de que los cambios se reflejen en la IU.StateFlow - Intenta escribir IU basadas en datos, donde la responsabilidad del controlador de IU sea
actualizar la IU a medida que los datos cambien o notificar las acciones del usuario al
ViewModel. - Coloca la lógica de datos en la
ViewModelclase.ViewModelfuncionará como el conector entre el controlador de IU y el resto de la app. Sin embargo, ten en cuenta que recuperar datos (por ejemplo, de una red) no es responsabilidad deViewModel. En cambio,ViewModeldebería realizar una llamada al componente apropiado para recuperar los datos y, luego, proporcionar los resultados a l controlador de IU. - Usa corutinas de Kotlin para administrar tareas de larga duración y otras operaciones que se pueden ejecutar de manera asíncrona.
- Mantén la lógica de inicio/detención dentro del elemento componible que realmente la necesita. De esta manera, la lógica se quita automáticamente si se quita ese elemento de la IU específico de la pantalla (por ejemplo, dentro de un gráfico de navegación o cuando la visibilidad es condicional).
- Usa
collectAsStateWithLifecyclepara los datos. No inicies ni detengas manualmente la recopilación deFlowen función de los eventos del ciclo de vida. En su lugar, usacollectAsStateWithLifecyclepara convertir flujos en estado de IU de manera eficiente. Esto ahorra batería y recursos porque losFlowse pausan cuando la app está en segundo plano.
Para obtener más información sobre Flow, consulta Otros tipos de estado compatibles.
Casos de uso de componentes optimizados para ciclos de vida
Los componentes optimizados para los ciclos de vida pueden facilitar la administración de los ciclos de vida en varios casos. Algunos ejemplos son los siguientes:
- Alternar entre actualizaciones de ubicación aproximadas o detalladas. Usa
LifecycleStartEffectpara habilitar actualizaciones de ubicación detalladas mientras tu app esté visible (ON_START) y limpia automáticamente el objeto de escucha o cambia a actualizaciones aproximadas cuando la app esté en segundo plano (ON_STOP). - Iniciar y detener el almacenamiento de videos en búfer. Usa
LifecycleResumeEffectpara diferir la reproducción de video real hasta que la app esté completamente en primer plano y sea interactiva (ON_RESUME) y para asegurarte de que la reproducción se pause y libere recursos cuando la app esté en segundo plano (ON_PAUSE). - Iniciar y detener la transmisión de red. Usa
collectAsStateWithLifecyclepara observar flujos continuos de datos (como un flujo de Kotlin desde un socket de red). Esto te brinda actualizaciones en vivo mientras una app está en primer plano y cancela automáticamente la recopilación cuando la app pasa a segundo plano. - Pausar y reanudar tareas pesadas. Usa
LifecycleResumeEffectpara controlar la pausa de actualizaciones visuales pesadas cuando la app está en segundo plano y reanudarlas después de que la app esté en primer plano.
Cómo controlar eventos ON_STOP de forma segura
Compose está diseñado para controlar eventos ON_STOP de forma segura.
- El estado es seguro: Puedes actualizar
MutableState(por ejemplo, conuiState.value = ...) en cualquier momento, incluso cuando la app está en segundo plano. Compose espera hasta que la app esté visible para renderizar los cambios. - Limpieza automática: Con efectos como
LifecycleStartEffect, tu bloque de limpieza (onStopOrDispose) se ejecuta exactamente cuando el ciclo de vida pasa aSTOPPED. Esto evita que mantengas recursos pesados (como la cámara o la ubicación) mientras la app está en segundo plano.
Para obtener más información sobre MutableState, consulta El estado y Jetpack Compose.
Recursos adicionales
Puedes obtener más información sobre la administración de los ciclos de vida con componentes optimizados para ciclos de vida en los siguientes recursos adicionales.
Contenido de Views
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Descripción general de LiveData
- Cómo usar las corrutinas de Kotlin con componentes optimizados para ciclos de vida
- Módulo de estado guardado para ViewModel