lifecycleScope — es un CoroutineScope integrado de la biblioteca androidx.lifecycle, vinculado al ciclo de vida de una Activity, Fragment o cualquier LifecycleOwner, y cancela automáticamente las corrutinas cuando el componente se destruye. Según Google Android Developers, 2025, lifecycleScope permite ejecutar corrutinas de forma segura en la capa de UI sin riesgo de ejecutar código después de que la Activity o Fragment se destruya. El scope se cancela automáticamente cuando el LifecycleOwner pasa al estado DESTROYED.
Conclusiones clave
lifecycleScope es una propiedad de extensión en la interfaz LifecycleOwner (Activity, Fragment, Service) que proporciona un CoroutineScope listo, vinculado al ciclo de vida completo del componente. Cuando el LifecycleOwner alcanza el estado DESTROYED, lifecycleScope cancela automáticamente todas las corrutinas activas.
// In Fragment or Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("¡Hola!")
}
A diferencia de viewModelScope, lifecycleScope se cancela cada vez que el LifecycleOwner se destruye — incluida la rotación de pantalla. Esto lo hace ideal para operaciones que solo deben vivir mientras una pantalla específica esté visible.
lifecycleScope está disponible en cualquier lugar donde haya un LifecycleOwner:
El mecanismo de cancelación automática de lifecycleScope se basa en la suscripción a eventos de Lifecycle. Cuando el Lifecycle baja de CREATED a DESTROYED, el scope se cancela.
| Estado | Descripción | Scope activo |
|---|---|---|
| CREATED | LifecycleOwner creado, onCreate ejecutado | Sí |
| STARTED | LifecycleOwner visible (onStart) | Sí |
| RESUMED | LifecycleOwner en primer plano (onResume) | Sí |
| DESTROYED | LifecycleOwner destruido (onDestroy) | No (scope cancelado) |
lifecycleScope se crea como CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) y se almacena dentro del Lifecycle. Cuando el Lifecycle transiciona al estado DESTROYED, se llama a scope.cancel(). El mecanismo se implementa a través de LifecycleEventObserver, que se suscribe a los eventos del ciclo de vida en el primer acceso al scope.
Cuando la pantalla se rota, la Activity se destruye (onDestroy) y se recrea. lifecycleScope se cancela junto con la Activity anterior, y se crea una nueva instancia del scope para la nueva Activity. Esta es una diferencia fundamental con viewModelScope, que sobrevive a la rotación.
La biblioteca lifecycle proporciona varias formas de lanzar corrutinas a través de lifecycleScope. Veamos la evolución de la API desde los métodos obsoletos hasta los modernos.
La forma más simple es lifecycleScope.launch { ... }. La corrutina se inicia inmediatamente y se cancela en DESTROYED. Sin embargo, puede ejecutar código incluso cuando la UI no es visible (por ejemplo, en segundo plano después de onStop). Esto no siempre es deseable.
Estos métodos pausaban la ejecución de la corrutina cuando el Lifecycle bajaba del estado especificado y la reanudaban al regresar. Sin embargo, fueron marcados como @Deprecated en lifecycle-runtime-ktx 2.6.0 porque:
repeatOnLifecycle es la forma recomendada por Google para lanzar corrutinas sincronizadas con el ciclo de vida. Cancela y reinicia la corrutina cada vez que el Lifecycle alcanza el estado especificado.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
La corrutina pasada a repeatOnLifecycle se inicia cuando el Lifecycle alcanza STARTED y se cancela cuando baja de STARTED. Al regresar a STARTED, la corrutina se reinicia desde cero. Esto es seguro y eficiente — ninguna corrutina queda en pausa.
Para recolectar datos de Flow con conciencia del ciclo de vida, existe el operador flowWithLifecycle. Detiene y reanuda automáticamente la recolección cuando cambia el estado del Lifecycle:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
El operador flowWithLifecycle es la forma más concisa de suscribirse de forma segura a un Flow en la capa de UI.
Veamos tres escenarios reales de uso de lifecycleScope en una aplicación Android con Kotlin.
class MapFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
locationProvider.observeLocation().collect { loc ->
updateMapMarker(loc)
}
}
}
}
}
La corrutina se inicia cuando el fragmento se vuelve visible (STARTED) y se cancela cuando sale de la pantalla (STOPPED). Si el usuario cambia a otra aplicación, las actualizaciones de ubicación no consumen batería.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
La animación se ejecuta solo cuando el fragmento está en primer plano (RESUMED). Si el usuario minimiza la aplicación durante la animación, la corrutina se cancela, y al regresar, la animación se reinicia.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
Los datos se sincronizan cada 30 segundos, pero solo cuando la pantalla es visible. isActive verifica si la corrutina ha sido cancelada, proporcionando una forma segura de salir del ciclo al salir de la pantalla.
Ambos scopes están vinculados al ciclo de vida, pero a diferentes aspectos del mismo. Comprender la diferencia es crítico para una arquitectura adecuada de aplicaciones Android.
viewModelScope está vinculado al ViewModel, que sobrevive a la rotación de pantalla. lifecycleScope está vinculado al LifecycleOwner (Activity/Fragment), que se destruye y recrea en la rotación. Esto determina sus casos de uso.
En la práctica, es común una combinación de ambos scopes: viewModelScope carga datos y gestiona el estado, mientras que lifecycleScope se suscribe al Flow del ViewModel con conciencia del ciclo de vida. Esta separación de responsabilidades se considera buena práctica en el desarrollo moderno de Android.
Veamos cuatro de los errores más comunes que cometen los desarrolladores al usar lifecycleScope.
Si se lanza la carga de datos en lifecycleScope.launch, la corrutina se cancelará al rotar la pantalla y los datos tendrán que cargarse de nuevo. Use viewModelScope para operaciones de larga duración. lifecycleScope es solo para tareas vinculadas a la UI.
Llamar directamente a viewModel.someFlow.collect { ... } dentro de lifecycleScope.launch continúa recolectando datos incluso cuando la pantalla no es visible. Esto puede provocar actualizaciones de UI en segundo plano y una sobrecarga innecesaria. Use siempre repeatOnLifecycle o flowWithLifecycle.
Aunque lifecycleScope se cancela en DESTROYED, el código después de un punto de suspensión puede no ejecutarse ante una cancelación repentina. No confíe en la ejecución posterior a una llamada suspend a menos que use NonCancellable.
launchWhenStarted y sus equivalentes no cancelan la corrutina, solo la pausan. Si la pantalla cambia entre primer plano y segundo plano varias veces, la corrutina acumula llamadas diferidas. Migre a repeatOnLifecycle — esta es la única forma correcta de sincronizarse con el Lifecycle.
Preguntas frecuentes
lifecycleScope se cancela automáticamente cuando el LifecycleOwner se destruye. GlobalScope vive durante toda la duración de la aplicación. Una corrutina en lifecycleScope no puede actualizar la UI después de que el componente se destruye, mientras que en GlobalScope puede hacerlo, lo que provoca fallos. Use siempre lifecycleScope en la capa de UI.
No, ViewModel no es un LifecycleOwner, por lo que lifecycleScope no está disponible en él. ViewModel usa viewModelScope. Si el código debe ejecutarse en ambos contextos, extraiga la lógica en un use case o repository con funciones suspend.
Cada llamada a repeatOnLifecycle crea una nueva corrutina que ejecuta el bloque cuando se alcanza el estado especificado del Lifecycle. Si se llama a repeatOnLifecycle dos veces para el mismo estado, ambos bloques se ejecutarán de forma independiente. Normalmente, una sola llamada en onViewCreated es suficiente.
No se puede cambiar directamente el dispatcher de lifecycleScope — usa Dispatchers.Main.immediate. Dentro del bloque de la corrutina, se puede cambiar a otro dispatcher mediante withContext. Para pruebas, use TestDispatcher con LifecycleOwner.
lifecycleScope se cancela cuando el LifecycleOwner transiciona al estado DESTROYED (después de onDestroy). Las llamadas simples a lifecycleScope.launch no se cancelan en onPause ni en onStop. Para pausar al ir a segundo plano, use repeatOnLifecycle(STARTED) o repeatOnLifecycle(RESUMED).
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también