Lifecycle in Jetpack Compose   Parte di Android Jetpack.

I componenti sensibili al ciclo di vita eseguono azioni in risposta a una modifica dello stato del ciclo di vita dell'attività host. L'artefatto androidx.lifecycle.compose fornisce API dedicate che liberano spazio automaticamente dalle risorse quando escono dallo schermo o quando l'applicazione va in background.

Le API principali includono:

Queste integrazioni forniscono hook pratici per gestire i cicli di vita all'interno della gerarchia di Compose. Questo documento descrive come utilizzarli nella tua app.

Raccogliere lo stato del ciclo di vita con i flussi

Lifecycle espone una proprietà currentStateFlow che fornisce l'Lifecycle.State corrente come StateFlow Kotlin. Puoi raccogliere questo Flow come State. In questo modo, la tua app può leggere le modifiche nel ciclo di vita durante la composizione.

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

val currentLifecycleState by stateFlow.collectAsState()

L'esempio precedente è accessibile utilizzando il modulo lifecycle-common. Il metodo currentStateAsState() è disponibile nel modulo lifecycle-runtime-compose, che ti consente di leggere comodamente lo stato attuale del ciclo di vita con una sola riga. L'esempio seguente lo dimostra:

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

Eseguire il codice sugli eventi del ciclo di vita

Anziché creare una classe separata che implementa DefaultLifecycleObserver e aggiungerla manualmente al ciclo di vita, puoi dichiarare la logica del ciclo di vita inline utilizzando effetti specifici. LifecycleEffects ti consente di eseguire un blocco quando si verifica un determinato Lifecycle.Event direttamente all'interno della composizione.

LifecycleEventEffect

Utilizza LifecycleEventEffect per eseguire un blocco di codice quando si verifica un evento specifico. Questa opzione è ideale per eventi una tantum come la registrazione o l'analisi, in cui non è necessario un risultato immediato o di successo.

@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

Per le operazioni di avvio/arresto accoppiate che devono essere eseguite durante l'avvio dell'app (visibile) e liberate spazio all'arresto dell'app (in background), utilizza LifecycleStartEffect.

Come altri effetti di Composizione (ad esempio LaunchedEffect), LifecycleStartEffect accetta chiavi. Quando la chiave cambia, il blocco viene eseguito di nuovo.

Quando si verifica un evento Lifecycle.Event.ON_STOP o l'effetto esce dalla composizione, viene eseguito il blocco onStopOrDispose per liberare spazio da qualsiasi lavoro che faceva parte del blocco iniziale.

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

Per informazioni su altri tipi di effetti collaterali, vedi Effetti collaterali in Compose.

LifecycleResumeEffect

LifecycleResumeEffect funziona allo stesso modo di LifecycleStartEffect, ma è associato all'evento Lifecycle.Event.ON_RESUME. Fornisce inoltre un blocco onPauseOrDispose che esegue la pulizia quando viene inviato ON_PAUSE o quando il composable esce dallo schermo.

Questa API è utile per le risorse che devono essere attive solo quando l'utente interagisce con l'app, ad esempio videocamere o animazioni.

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

        onPauseOrDispose {
            cameraController.stopPreview()
        }
    }
}

Accedere a LifecycleOwner

In Compose, l'LifecycleOwner è disponibile implicitamente tramite CompositionLocal denominato LocalLifecycleOwner. Per impostazione predefinita, l'host principale della gerarchia di composizione fornisce questo proprietario.

val lifecycleOwner = LocalLifecycleOwner.current

Per molte app, l'ispezione di questo proprietario predefinito o il suo passaggio a effetti sensibili al ciclo di vita è sufficiente. Tuttavia, per la navigazione personalizzata o i layout complessi, potresti voler creare il tuo LifecycleOwner per definire gli stati del ciclo di vita in sezioni specifiche della UI. Ad esempio, le librerie di navigazione (come Navigation 3) lo fanno automaticamente per dare a ogni singola schermata il proprio ciclo di vita.

Crea un LifecycleOwner personalizzato

L'API rememberLifecycleOwner() ti consente di creare e memorizzare un LifecycleOwner personalizzato. Ciò è particolarmente utile per componenti come un HorizontalPager, in cui vuoi che solo la pagina visibile e stabile sia RESUMED, mentre imposti un maxState di STARTED per le pagine adiacenti e fuori schermo.

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

Per ulteriori informazioni su CompositionLocal, consulta Dati con ambito locale con CompositionLocal.

Best practice per i componenti sensibili al ciclo di vita

  • Mantieni i controller dell'interfaccia utente il più semplici possibile. Non deve tentare di acquisire i propri dati; utilizza invece un ViewModel per farlo e osserva un oggetto StateFlow per riflettere le modifiche nell'interfaccia utente.
  • Prova a scrivere UI basate sui dati in cui la responsabilità del controller UI è quella di aggiornare la UI man mano che i dati cambiano o notificare le azioni dell'utente al ViewModel.
  • Inserisci la logica dei dati nella classe ViewModel. ViewModel deve fungere da connettore tra il controller UI e il resto dell'app. Fai attenzione, però, non è responsabilità di ViewModel recuperare i dati (ad esempio da una rete). Invece, ViewModel deve chiamare il componente appropriato per recuperare i dati, quindi fornire il risultato al controller UI.
  • Utilizza le coroutine Kotlin per gestire le attività a lunga esecuzione e altre operazioni che possono essere eseguite in modo asincrono.
  • Mantieni la logica di avvio/arresto all'interno del composable che ne ha effettivamente bisogno. In questo modo, la logica viene rimossa automaticamente se questo specifico elemento dell'interfaccia utente viene rimosso dalla schermata (ad esempio, all'interno di un grafico di navigazione o quando la visibilità è condizionale).
  • Utilizza collectAsStateWithLifecycle per i dati. Non avviare o interrompere manualmente la raccolta Flow in base agli eventi del ciclo di vita. Utilizza invece collectAsStateWithLifecycle per convertire i flussi in stato della UI in modo efficiente. In questo modo si risparmiano batteria e risorse perché le Flow vengono messe in pausa quando l'app è in background.

Per ulteriori informazioni sugli Flow, vedi Altri tipi di stato supportati.

Casi d'uso per i componenti sensibili al ciclo di vita

I componenti sensibili al ciclo di vita possono semplificare notevolmente la gestione dei cicli di vita in una serie di casi. Ecco alcuni esempi:

  • Alternare gli aggiornamenti della posizione approssimativa e precisa. Utilizza LifecycleStartEffect per attivare aggiornamenti della posizione granulari mentre la tua app è visibile (ON_START) e libera spazio automaticamente per il listener o passa ad aggiornamenti meno granulari quando l'app è in background (ON_STOP).
  • Interruzione e avvio del buffering video. Utilizza LifecycleResumeEffect per posticipare la riproduzione effettiva del video finché l'app non è completamente in primo piano e interattiva (ON_RESUME) e per assicurarti che la riproduzione si interrompa e rilasci le risorse quando l'app viene eseguita in background (ON_PAUSE).
  • Avvio e interruzione dello streaming di rete. Utilizza collectAsStateWithLifecycle per osservare flussi continui di dati (come un flusso Kotlin da un socket di rete). In questo modo, l'aggiornamento avviene in tempo reale mentre un'app è in primo piano e la raccolta viene annullata automaticamente quando l'app passa in background.
  • Mettere in pausa e riprendere le attività pesanti. Utilizza LifecycleResumeEffect per gestire la sospensione degli aggiornamenti visivi pesanti quando l'app è in background e riprendili dopo che l'app è in primo piano.

Gestione sicura degli eventi ON_STOP

Compose è progettato per gestire in sicurezza gli eventi ON_STOP.

  • Stato sicuro:puoi aggiornare MutableState (ad esempio con uiState.value = ...) in qualsiasi momento, anche quando l'app è in background. Compose attende che l'app sia visibile per eseguire il rendering delle modifiche.
  • Pulizia automatica:con effetti come LifecycleStartEffect, il blocco di pulizia (onStopOrDispose) viene eseguito esattamente quando il ciclo di vita passa a STOPPED. In questo modo, non puoi utilizzare risorse pesanti (come la fotocamera o la posizione) mentre l'app è in background.

Per saperne di più su MutableState, consulta Stato in Jetpack Compose.

Risorse aggiuntive

Per scoprire di più sulla gestione dei cicli di vita con componenti sensibili al ciclo di vita, consulta le seguenti risorse aggiuntive.

Visualizza contenuti