LifecycleOwner — est une interface clé de la bibliothèque Android Jetpack qui déclare qu'un objet possède un cycle de vie et donne accès à celui-ci via la méthode getLifecycle(). Elle est au cœur de l'architecture des composants des applications Android modernes, permettant de séparer la logique de gestion du cycle de vie de l'implémentation concrète d'une Activity ou d'un Fragment. Selon Google I/O 2024, plus de 85% des nouveaux projets Android utilisent LifecycleOwner pour gérer les abonnements et prévenir les fuites mémoire. Cette interface est le fondement de LiveData, ViewModel et d'autres composants Jetpack, garantissant l'exécution sécurisée du code uniquement dans l'état actif du composant.
Points essentiels
LifecycleOwner — est une interface du package androidx.lifecycle qui contient une seule méthode getLifecycle() retournant un objet Lifecycle. Cet objet suit l'état actuel du composant (CREATED, STARTED, RESUMED, DESTROYED) et notifie tous les observateurs abonnés lors de son changement. LifecycleOwner fait partie des Architecture Components et est inclus dans la bibliothèque lifecycle-runtime.
La tâche principale de l'interface est de standardiser l'accès au cycle de vie. Avant Jetpack, les développeurs utilisaient un abonnement manuel dans onStart et un désabonnement dans onStop, ce qui entraînait une duplication de code et des erreurs. LifecycleOwner résout ce problème en fournissant un mécanisme unifié pour tous les composants Android. Au lieu d'appeler explicitement les méthodes du cycle de vie, le développeur s'abonne une fois au Lifecycle et les notifications arrivent automatiquement.
L'interface est déclarée en Kotlin comme une interface fonctionnelle avec une seule méthode abstraite :
interface LifecycleOwner {
val lifecycle: Lifecycle
}
Grâce à la nature fonctionnelle de l'interface, elle est facile à implémenter avec un délégué ou une lambda. C'est particulièrement pratique pour créer des Custom Views et des classes ViewModel qui doivent réagir aux changements du cycle de vie de l'hôte. L'objet Lifecycle obtenu de getLifecycle() fournit les méthodes addObserver et removeObserver pour gérer les abonnements.
LifecycleOwner fonctionne de concert avec deux classes clés : Lifecycle et LifecycleObserver. Lifecycle stocke l'état actuel du composant sous forme d'enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) et suit les transitions entre eux. Lorsque l'état change, Lifecycle notifie tous les observateurs enregistrés en appelant les méthodes annotées correspondantes. Ce mécanisme est appelé "lifecycle-aware" — le code n'est exécuté que lorsque le composant est dans un état approprié.
Le mécanisme de transmission des événements est basé sur le patron Observer. LifecycleOwner agit comme Observable, et l'implémentation de LifecycleObserver comme Observer. L'Activity ou le Fragment, lors du changement de son état (onCreate → onStart → onResume → onPause → onStop → onDestroy), notifie le Lifecycle via le mécanisme interne ReportFragment qui est ajouté automatiquement au système AndroidX. Le développeur n'a pas besoin d'appeler manuellement les méthodes du Lifecycle — tout se fait automatiquement.
| État Lifecycle | Événement | Méthode du cycle de vie Android |
|---|---|---|
| INITIALIZED | — | Avant onCreate |
| CREATED | ON_CREATE | onCreate |
| STARTED | ON_START | onStart |
| RESUMED | ON_RESUME | onResume |
| STARTED | ON_PAUSE | onPause |
| CREATED | ON_STOP | onStop |
| DESTROYED | ON_DESTROY | onDestroy |
Un détail important : Lifecycle garantit que les événements ON_STOP et ON_DESTROY seront délivrés même en cas de crash du processus. Cela fait de LifecycleOwner un outil fiable pour libérer des ressources critiques. Pour la sauvegarde d'état classique, il est recommandé d'utiliser SavedStateHandle dans ViewModel, mais LifecycleOwner offre un niveau de sécurité de base.
Il existe deux façons de s'abonner aux événements de LifecycleOwner : le classique LifecycleObserver avec annotations et le moderne DefaultLifecycleObserver avec méthodes explicites. La deuxième approche est recommandée par Google depuis 2022 car elle offre une meilleure sécurité de typage et évite la réflexion utilisée dans l'approche par annotations. DefaultLifecycleObserver nécessite Java 8+ ou Kotlin et est préféré pour les nouveaux projets.
Exemple d'abonnement via DefaultLifecycleObserver :
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// Démarrer le suivi GPS uniquement lorsque le composant est actif
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// Arrêt sécurisé lors du passage en mode arrière-plan
stopLocationUpdates()
}
}
// Connexion :
lifecycleOwner.lifecycle.addObserver(MyObserver())
Chaque méthode de DefaultLifecycleObserver accepte LifecycleOwner comme paramètre. Cela permet à l'observateur d'accéder au contexte du composant en cours d'exécution sans avoir à le transmettre séparément. Cette approche rend le code plus modulaire et testable — l'Observer ne dépend pas d'une implémentation spécifique d'Activity ou de Fragment, mais travaille avec l'abstraction LifecycleOwner.
L'ancienne méthode avec l'annotation @OnLifecycleEvent se rencontre encore dans les projets legacy, mais son utilisation n'est pas recommandée pour le nouveau code. La réflexion nécessaire au traitement des annotations ajoute une surcharge et peut entraîner des erreurs non détectées à la compilation. Google conseille officiellement de migrer vers DefaultLifecycleObserver.
// Approche obsolète — non recommandée pour les nouveaux projets
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
L'approche par annotation a un inconvénient majeur : l'absence de contrôle de la durée de vie de l'Observer. Si le développeur oublie de désabonner l'Observer lors de la destruction du LifecycleOwner, l'objet Observer reste en mémoire jusqu'à l'appel du garbage collector. DefaultLifecycleObserver résout ce problème — l'Observer est lié au Lifecycle et se désabonne automatiquement lors du passage à l'état DESTROYED.
À partir d'AppCompat 1.1.0 et AndroidX Fragment 1.2.0, toutes les Activities et Fragments qui héritent d'AppCompatActivity ou de Fragment sont automatiquement LifecycleOwner. Cela signifie que la méthode getLifecycle() est disponible par défaut et que l'abonnement aux événements du cycle de vie fonctionne sans configuration supplémentaire. Le développeur a simplement besoin d'appeler lifecycle.addObserver() depuis n'importe quel endroit dans l'Activity ou le Fragment.
Prenons un exemple d'intégration de LifecycleOwner dans une Activity :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
Dans cet exemple, lifecycle est une extension property disponible grâce à l'AndroidX Activity. L'observateur LocationObserver recevra automatiquement les notifications de démarrage (ON_START) et d'arrêt (ON_STOP) de l'Activity. Lors de la rotation de l'écran, l'Observer est notifié de ON_DESTROY puis ON_CREATE, ce qui permet de gérer correctement les changements de configuration sans code supplémentaire.
Fragment implémente LifecycleOwner via l'interface, et son Lifecycle est lié au cycle de vie du Fragment, pas à celui de l'Activity parente. C'est important : le Lifecycle du Fragment passe à DESTROYED lorsque le Fragment est retiré de la transaction, tandis que l'Activity peut rester en RESUMED. Cette différence permet à l'Observer de s'abonner séparément au cycle de vie de chaque composant.
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
Un avantage important de l'utilisation de LifecycleOwner dans Fragment est le désabonnement automatique lors du passage du Fragment en DESTROYED. C'est particulièrement pertinent pour ViewPager, où les Fragments peuvent être créés et détruits dynamiquement. La gestion manuelle des abonnements dans ce scénario serait extrêmement complexe et sujette aux erreurs.
L'interface LifecycleOwner peut être implémentée dans n'importe quelle classe ayant un cycle de vie. C'est utile pour les Custom Views, les Services et même les ViewModel dans certaines solutions architecturales. Google fournit la classe utilitaire LifecycleRegistry qui gère l'état du Lifecycle et génère les événements. Le développeur doit appeler manuellement les méthodes correspondantes de LifecycleRegistry lors du changement d'état du composant.
Exemple d'implémentation de LifecycleOwner dans une Custom View :
class MyCustomView(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs), LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle
get() = lifecycleRegistry
fun onStart() {
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED)
}
fun onStop() {
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED)
}
}
Dans cet exemple, LifecycleRegistry agit comme un stockage d'état. Les méthodes onStart/onStop doivent être appelées par le composant parent (par exemple l'Activity) lorsque la Custom View devient visible ou est masquée. LifecycleRegistry calcule automatiquement les événements nécessaires à la transition entre les états et notifie tous les Observers abonnés.
Lors de l'implémentation de votre propre LifecycleOwner, il est important de respecter la règle : l'état de LifecycleRegistry doit être mis à jour en dernier dans la méthode du cycle de vie correspondante, après toutes les autres opérations. Cela garantit que l'Observer reçoit la notification lorsque le composant est déjà complètement prêt pour le nouvel état. L'utilisation de LifecycleRegistry.createUnsafe comme alternative est également possible, mais nécessite de la prudence avec les threads.
LifecycleOwner est le fondement de plusieurs composants clés d'Android Jetpack. LiveData utilise LifecycleOwner pour déterminer l'état actif et se désabonner automatiquement lors de la destruction du composant. ViewModel n'implémente pas directement LifecycleOwner mais peut obtenir Lifecycle via SavedStateHandle. Navigation Component utilise LifecycleOwner pour gérer les abonnements dans NavBackStackEntry. Comprendre cette interrelation aide à construire une architecture d'application sur des bases solides.
Interaction de LiveData avec LifecycleOwner :
class ExampleActivity : AppCompatActivity() {
private val viewModel: ExampleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.userData.observe(this) { data ->
// this — LifecycleOwner (Activity)
// Le code n'est exécuté que lorsque l'Activity est dans l'état RESUMED
updateUI(data)
}
}
}
LiveData requiert LifecycleOwner dans la méthode observe() car cela garantit que les mises à jour de l'interface utilisateur ne se produisent que dans l'état actif. Si l'Activity est en arrière-plan, LiveData conserve la dernière valeur mais ne notifie pas l'Observer. Lors du retour à RESUMED, l'Observer reçoit la valeur actuelle sans requêtes réseau ou base de données supplémentaires.
DataBinding utilise également LifecycleOwner pour lier les champs observables au cycle de vie de l'Activity ou du Fragment. Cela permet d'éviter les fuites mémoire dans la combinaison ViewModel + DataBinding — tous les abonnements sont automatiquement nettoyés lors de la destruction du LifecycleOwner. Cette approche rend le code déclaratif et sécurisé.
L'utilisation correcte de LifecycleOwner nécessite le respect de plusieurs règles clés. La première et la plus importante : abonnez toujours l'Observer dans onCreate/onViewCreated, pas plus tard. Cela garantit que l'Observer reçoit l'état initial du Lifecycle (CREATED après onCreate) et ne manque pas d'événements. Deuxième règle : utilisez DefaultLifecycleObserver plutôt que l'approche par annotations pour tous les nouveaux projets.
L'approche moderne pour travailler avec les coroutines et LifecycleOwner — l'extension repeatOnLifecycle :
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
Ce motif garantit que le collect sur Flow n'est actif que dans l'état STARTED ou RESUMED. Lors du passage à STOPPED, la collecte est automatiquement annulée et au retour à STARTED, elle est redémarrée. repeatOnLifecycle remplace le désabonnement manuel de Flow dans Fragment et est l'approche recommandée par Google pour travailler avec des flux de données asynchrones dans les composants d'interface utilisateur.
Une autre recommandation importante : n'abusez pas de LifecycleObserver pour une logique non liée au cycle de vie. Si un composant doit exécuter une action dans un état spécifique mais ne nécessite pas de désabonnement à la destruction, il est préférable d'utiliser des appels de méthodes explicites dans onStart/onStop. LifecycleObserver est justifié pour les composants à longue durée de vie (LocationListener, SensorManager) où la gestion manuelle des abonnements est complexe et sujette aux erreurs.
Questions fréquentes
LifecycleOwner — est une interface qui déclare qu'un objet a un cycle de vie. Lifecycle — est une classe qui stocke l'état actuel et gère les Observers. LifecycleOwner fournit le Lifecycle via getLifecycle().
Non, Lifecycle désabonne automatiquement tous les Observers lors du passage à DESTROYED. C'est l'un des principaux avantages de LifecycleOwner — le développeur n'a pas besoin d'appeler manuellement removeObserver dans onDestroy.
Fragment implémente LifecycleOwner via l'interface des fragments AndroidX. Son Lifecycle est lié au cycle de vie du Fragment séparément de l'Activity. Cela permet à l'Observer de réagir spécifiquement aux événements du Fragment, pas de l'Activity parente.
Oui, pour cela on utilise LifecycleRegistry. La Custom View doit implémenter l'interface LifecycleOwner et mettre à jour manuellement l'état de LifecycleRegistry lors des changements de visibilité ou d'attachement à la fenêtre.
LifecycleOwner résout un problème différent : la gestion des abonnements aux événements du cycle de vie, pas l'annulation des coroutines. Pour les coroutines, on utilise lifecycleScope qui annule automatiquement les coroutines en cours lors de la destruction du LifecycleOwner.
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