Cycle de vie dans Jetpack Compose   Fait partie d'Android Jetpack.

Les composants tenant compte des cycles de vie effectuent des actions en réponse à une modification de l'état du cycle de vie de l'activité hôte. L' androidx.lifecycle.compose artefact fournit des API dédiées qui nettoient automatiquement les ressources lorsqu'elles quittent l'écran ou lorsque l'application passe en arrière-plan.

Voici les API principales :

Ces intégrations fournissent des hooks pratiques pour gérer les cycles de vie dans la hiérarchie de Compose. Ce document explique comment les utiliser dans votre application.

Collecter l'état du cycle de vie avec des flux

Lifecycle expose une propriété currentStateFlow qui fournit le Lifecycle.State actuel sous la forme d'un StateFlow Kotlin. Vous pouvez collecter ce Flow en tant que State. Cela permet à votre application de lire les modifications apportées au cycle de vie pendant la composition.

val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow

val currentLifecycleState by stateFlow.collectAsState()

L'exemple précédent est accessible à l'aide du module lifecycle-common. La méthode currentStateAsState() est disponible dans le module lifecycle-runtime-compose, qui vous permet de lire facilement l'état actuel du cycle de vie sur une seule ligne. En voici un bon exemple :

val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()

Exécuter du code sur des événements de cycle de vie

Au lieu de créer une classe distincte qui implémente DefaultLifecycleObserver et de l'ajouter manuellement au cycle de vie, vous pouvez déclarer la logique du cycle de vie en ligne à l'aide d'effets spécifiques. LifecycleEffects vous permet d'exécuter un bloc lorsqu'un Lifecycle.Event spécifique se produit directement dans la composition.

LifecycleEventEffect

Utilisez LifecycleEventEffect pour exécuter un bloc de code lorsqu'un événement spécifique se produit. Cette méthode est idéale pour les événements ponctuels tels que la journalisation ou l'analyse, où ni la réussite ni un résultat immédiat ne sont nécessaires.

@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

Pour les opérations de démarrage/arrêt appariées qui doivent s'exécuter lorsque l'application est démarrée (visible) et être nettoyées lorsqu'elle est arrêtée (en arrière-plan), utilisez LifecycleStartEffect.

Comme d'autres effets Compose (tels que LaunchedEffect), LifecycleStartEffect accepte les clés. Un changement de clé déclenche une nouvelle exécution du bloc.

Lorsqu'un événement Lifecycle.Event.ON_STOP se produit ou que l'effet quitte la composition, le bloc onStopOrDispose est exécuté pour nettoyer toute tâche qui faisait partie du bloc de départ.

@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)
        }
    }
}

Pour en savoir plus sur les autres types d'effets secondaires, consultez Effets secondaires dans Compose.

LifecycleResumeEffect

LifecycleResumeEffect fonctionne de la même manière que LifecycleStartEffect, mais est lié à l'événement Lifecycle.Event.ON_RESUME. Il fournit également un bloc onPauseOrDispose qui effectue le nettoyage lorsque ON_PAUSE est distribué ou que le composable quitte l'écran.

Cette API est utile pour les ressources qui ne doivent être actives que lorsque l'utilisateur interagit avec l'application (par exemple, les caméras ou les animations).

@Composable
fun CameraPreview(cameraController: CameraController) {
    LifecycleResumeEffect(cameraController) {
        cameraController.startPreview()

        onPauseOrDispose {
            cameraController.stopPreview()
        }
    }
}

Accéder à LifecycleOwner

Dans Compose, le LifecycleOwner est implicitement disponible via le CompositionLocal nommé LocalLifecycleOwner. Par défaut, l'hôte racine de votre hiérarchie de composition fournit ce propriétaire.

val lifecycleOwner = LocalLifecycleOwner.current

Pour de nombreuses applications, il suffit d'inspecter ce propriétaire par défaut ou de le transmettre à des effets tenant compte du cycle de vie. Toutefois, pour une navigation personnalisée ou des mises en page complexes, vous pouvez créer votre propre LifecycleOwner afin de limiter les états du cycle de vie à des sections spécifiques de l'UI. Par exemple, les bibliothèques de navigation (comme Navigation 3) le font automatiquement pour attribuer à chaque écran son propre cycle de vie.

Créer un LifecycleOwner personnalisé

L'API rememberLifecycleOwner() vous permet de créer et de mémoriser un personnaliséLifecycleOwner. Cela est particulièrement utile pour les composants tels que HorizontalPager, où vous ne souhaitez que la page visible et établie soit RESUMED, tout en définissant un maxState de STARTED pour les pages adjacentes hors écran.

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.
    }
}

Pour en savoir plus sur CompositionLocal, consultez Données à champ d'application local avec CompositionLocal.

Bonnes pratiques concernant les composants tenant compte des cycles de vie

  • Faites en sorte que vos contrôleurs d'interface utilisateur soient aussi légers que possible. Ils ne doivent pas essayer d'acquérir leurs propres données. Pour ce faire, utilisez un ViewModel et observez un StateFlow qui reflète les modifications apportées sur l'UI.
  • Essayez de créer des interfaces utilisateur basées sur les données pour lesquelles votre contrôleur d'interface utilisateur est chargé de mettre à jour l'UI à mesure que les données changent, ou de transmettre les actions des utilisateurs au ViewModel.
  • Placez votre logique de données dans la ViewModel classe. ViewModel doit servir de connecteur entre votre contrôleur d'interface utilisateur et le reste de votre application. Soyez prudent, car ViewModel n'est pas responsable de la récupération de données (à partir d'un réseau, par exemple). Au lieu de cela, ViewModel doit appeler le composant approprié pour récupérer les données, puis renvoyer le résultat à le contrôleur d'interface utilisateur.
  • Utilisez les coroutines Kotlin pour gérer les tâches de longue durée et les autres opérations pouvant s'exécuter de manière asynchrone.
  • Conservez la logique de démarrage/arrêt dans le composable qui en a réellement besoin. Ainsi, la logique est automatiquement supprimée si cet élément d'interface utilisateur spécifique est supprimé de l'écran (par exemple, dans un graphique de navigation ou lorsque la visibilité est conditionnelle).
  • Utilisez collectAsStateWithLifecycle pour les données. Ne démarrez ni n'arrêtez manuellement la collecte Flow en fonction des événements de cycle de vie. Utilisez plutôt collectAsStateWithLifecycle pour convertir efficacement les flux en état d'UI. Cela permet d'économiser la batterie et les ressources, car les Flow sont mis en pause lorsque l'application est en arrière-plan.

Pour en savoir plus sur les Flow, consultez Autres types d'état compatibles.

Cas d'utilisation des composants tenant compte des cycles de vie

Les composants tenant compte des cycles de vie peuvent faciliter considérablement la gestion des cycles de vie dans de nombreux cas. Voici quelques exemples :

  • Alterner entre des mises à jour de position plus ou moins précises. Utilisez LifecycleStartEffect pour obtenir des mises à jour précises de la position lorsque votre application est visible (ON_START), et nettoyez automatiquement l'écouteur ou passez à des mises à jour moins précises lorsque l'application est en arrière-plan (ON_STOP).
  • Arrêt et démarrage de la mise en mémoire tampon de vidéos. Utilisez LifecycleResumeEffect pour différer la lecture vidéo réelle jusqu'à ce que l'application soit entièrement au premier plan et interactive (ON_RESUME), et pour vous assurer que la lecture est mise en pause et que les ressources sont libérées lorsque l'application est en arrière-plan (ON_PAUSE).
  • Démarrage et arrêt de la diffusion réseau. Utilisez collectAsStateWithLifecycle pour observer les flux de données continus (comme un Kotlin Flow à partir d'un socket réseau). Cela vous permet d'obtenir des mises à jour en direct lorsqu'une application est au premier plan et d'annuler automatiquement la collecte lorsque l'application passe en arrière-plan.
  • Mise en pause et reprise des tâches lourdes. Utilisez LifecycleResumeEffect pour gérer la mise en pause des mises à jour visuelles lourdes lorsque l'application est en arrière-plan, et les reprendre une fois qu'elle passe au premier plan.

Gérer les événements ON_STOP en toute sécurité

Compose est conçu pour gérer les événements ON_STOP en toute sécurité.

  • L'état est sécurisé : vous pouvez mettre à jour MutableState (par exemple, avec uiState.value = ...) à tout moment, même lorsque l'application est en arrière-plan. Compose attend que l'application soit visible pour afficher les modifications.
  • Nettoyage automatique : avec des effets tels que LifecycleStartEffect, votre bloc de nettoyage (onStopOrDispose) s'exécute exactement lorsque le cycle de vie passe à STOPPED. Cela vous évite de conserver des ressources lourdes (comme une caméra ou une position) lorsque l'application est en arrière-plan.

Pour en savoir plus sur MutableState, consultez États et Jetpack Compose.

Ressources supplémentaires

Pour en savoir plus sur la gestion des cycles de vie avec des composants qui tiennent compte des cycles de vie, consultez les ressources supplémentaires suivantes.

Afficher le contenu