lifecycleScope est un CoroutineScope intégré de la bibliothèque androidx.lifecycle, lié au cycle de vie d’une Activity, d’un Fragment ou de tout LifecycleOwner, et annule automatiquement les coroutines lorsque le composant est détruit. Selon Google Android Developers, 2025, lifecycleScope permet d’exécuter en toute sécurité des coroutines liées à la couche UI sans risque d’exécuter du code après la destruction de l’Activity ou du Fragment. Le scope est automatiquement annulé lorsque le LifecycleOwner passe à l’état DESTROYED.
Points clés
lifecycleScope est une propriété d’extension sur l’interface LifecycleOwner (Activity, Fragment, Service) qui fournit un CoroutineScope prêt à l’emploi, lié au cycle de vie complet du composant. Lorsque le LifecycleOwner atteint l’état DESTROYED, lifecycleScope annule automatiquement toutes les coroutines actives.
// In Fragment or Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("Bonjour !")
}
Contrairement à viewModelScope, lifecycleScope est annulé chaque fois que le LifecycleOwner est détruit — y compris lors de la rotation de l’écran. Cela le rend idéal pour les opérations qui ne doivent vivre que tant qu’un écran spécifique est visible.
lifecycleScope est disponible partout où il y a un LifecycleOwner :
Le mécanisme d’annulation automatique de lifecycleScope repose sur l’abonnement aux événements Lifecycle. Lorsque le Lifecycle descend en dessous de CREATED vers DESTROYED, le scope est annulé.
| État | Description | Scope actif |
|---|---|---|
| CREATED | LifecycleOwner créé, onCreate exécuté | Oui |
| STARTED | LifecycleOwner visible (onStart) | Oui |
| RESUMED | LifecycleOwner au premier plan (onResume) | Oui |
| DESTROYED | LifecycleOwner détruit (onDestroy) | Non (scope annulé) |
lifecycleScope est créé en tant que CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) et stocké à l’intérieur du Lifecycle. Lorsque le Lifecycle passe à l’état DESTROYED, scope.cancel() est appelé. Le mécanisme est implémenté via LifecycleEventObserver, qui s’abonne aux événements du cycle de vie lors du premier accès au scope.
Lorsque l’écran est pivoté, l’Activity est détruite (onDestroy) et recréée. lifecycleScope est annulé avec l’ancienne Activity, et une nouvelle instance du scope est créée pour la nouvelle Activity. C’est une différence fondamentale avec viewModelScope, qui survit à la rotation.
La bibliothèque lifecycle fournit plusieurs façons de lancer des coroutines via lifecycleScope. Examinons l’évolution de l’API des méthodes obsolètes aux méthodes modernes.
La façon la plus simple est lifecycleScope.launch { ... }. La coroutine démarre immédiatement et est annulée à DESTROYED. Cependant, elle peut exécuter du code même lorsque l’UI n’est pas visible (par exemple, en arrière-plan après onStop). Ce n’est pas toujours souhaitable.
Ces méthodes mettaient en pause l’exécution de la coroutine lorsque le Lifecycle descendait en dessous de l’état spécifié et la reprenaient au retour. Cependant, elles ont été marquées @Deprecated dans lifecycle-runtime-ktx 2.6.0 parce que :
repeatOnLifecycle est la méthode recommandée par Google pour lancer des coroutines synchronisées avec le cycle de vie. Elle annule et redémarre la coroutine chaque fois que le Lifecycle atteint l’état spécifié.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
La coroutine passée à repeatOnLifecycle démarre lorsque le Lifecycle atteint STARTED et est annulée lorsqu’il descend en dessous de STARTED. Au retour à STARTED, la coroutine redémarre depuis le début. C’est sûr et efficace — aucune coroutine ne reste suspendue.
Pour collecter des données à partir de Flow avec une connaissance du cycle de vie, il existe l’opérateur flowWithLifecycle. Il arrête et reprend automatiquement la collecte lorsque l’état du Lifecycle change :
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
L’opérateur flowWithLifecycle est la façon la plus concise de s’abonner en toute sécurité à un Flow dans la couche UI.
Examinons trois scénarios réels d’utilisation de lifecycleScope dans une application Android avec 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 coroutine démarre lorsque le fragment devient visible (STARTED) et est annulée lorsqu’il quitte l’écran (STOPPED). Si l’utilisateur passe à une autre application, les mises à jour de localisation ne consomment pas la batterie.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
L’animation s’exécute uniquement lorsque le fragment est au premier plan (RESUMED). Si l’utilisateur minimise l’application pendant l’animation, la coroutine est annulée et, au retour, l’animation redémarre.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
Les données sont synchronisées toutes les 30 secondes, mais uniquement lorsque l’écran est visible. isActive vérifie si la coroutine a été annulée, offrant une sortie sûre de la boucle lors de la sortie de l’écran.
Les deux scopes sont liés au cycle de vie, mais à des aspects différents de celui-ci. Comprendre la différence est crucial pour une architecture correcte des applications Android.
viewModelScope est lié au ViewModel, qui survit à la rotation de l’écran. lifecycleScope est lié au LifecycleOwner (Activity/Fragment), qui est détruit et recréé lors de la rotation. Cela détermine leurs scénarios d’utilisation.
En pratique, une combinaison des deux scopes est courante : viewModelScope charge les données et gère l’état, tandis que lifecycleScope s’abonne au Flow du ViewModel avec une connaissance du cycle de vie. Cette séparation des responsabilités est considérée comme une bonne pratique dans le développement Android moderne.
Examinons quatre des erreurs les plus courantes que les développeurs commettent lors de l’utilisation de lifecycleScope.
Si vous lancez le chargement de données dans lifecycleScope.launch, la coroutine sera annulée lors de la rotation de l’écran et les données devront être rechargées. Utilisez viewModelScope pour les opérations de longue durée. lifecycleScope est uniquement pour les tâches liées à l’UI.
Appeler directement viewModel.someFlow.collect { ... } dans lifecycleScope.launch continue de collecter des données même lorsque l’écran n’est pas visible. Cela peut entraîner des mises à jour de l’UI en arrière-plan et une surcharge inutile. Utilisez toujours repeatOnLifecycle ou flowWithLifecycle.
Bien que lifecycleScope soit annulé à DESTROYED, le code après un point de suspension peut ne pas s’exécuter en cas d’annulation soudaine. Ne comptez pas sur l’exécution du code après un appel suspend, sauf si vous utilisez NonCancellable.
launchWhenStarted et ses équivalents n’annulent pas la coroutine, ils la mettent seulement en pause. Si l’écran bascule plusieurs fois entre le premier plan et l’arrière-plan, la coroutine accumule des appels différés. Passez à repeatOnLifecycle — c’est la seule façon correcte de se synchroniser avec le Lifecycle.
Questions fréquentes
lifecycleScope est automatiquement annulé lorsque le LifecycleOwner est détruit. GlobalScope vit pendant toute la durée de l’application. Une coroutine dans lifecycleScope ne peut pas mettre à jour l’UI après la destruction du composant, contrairement à GlobalScope, ce qui entraîne des plantages. Utilisez toujours lifecycleScope dans la couche UI.
Non, ViewModel n’est pas un LifecycleOwner, donc lifecycleScope n’y est pas disponible. ViewModel utilise viewModelScope. Si le code doit s’exécuter dans les deux contextes, extrayez la logique dans un use case ou un repository avec des fonctions suspend.
Chaque appel à repeatOnLifecycle crée une nouvelle coroutine qui exécute le bloc lorsque l’état spécifié du Lifecycle est atteint. Si repeatOnLifecycle est appelé deux fois pour le même état, les deux blocs s’exécuteront indépendamment. Généralement, un seul appel dans onViewCreated suffit.
Vous ne pouvez pas modifier directement le dispatcher de lifecycleScope — il utilise Dispatchers.Main.immediate. À l’intérieur du bloc de coroutine, vous pouvez passer à un autre dispatcher via withContext. Pour les tests, utilisez TestDispatcher avec LifecycleOwner.
lifecycleScope est annulé lorsque le LifecycleOwner passe à l’état DESTROYED (après onDestroy). Les simples appels lifecycleScope.launch ne sont pas annulés dans onPause ou onStop. Pour mettre en pause lors du passage en arrière-plan, utilisez repeatOnLifecycle(STARTED) ou repeatOnLifecycle(RESUMED).
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi