Il ciclo di vita dell'attività

Man mano che un utente naviga all'interno della tua app, esce e poi torna, le istanze Activity della tua app passano attraverso diversi stati del loro ciclo di vita. La classe Activity fornisce una serie di callback che consentono all'attività di sapere quando uno stato cambia o che il sistema sta creando, arrestando o riprendendo un'attività o distruggendo il processo in cui risiede l'attività.

All'interno dei metodi di callback del ciclo di vita, puoi dichiarare il comportamento dell'attività quando l'utente esce e rientra nell'attività. Ad esempio, se stai creando un video player in streaming, potresti mettere in pausa il video e interrompere la connessione di rete quando l'utente passa a un'altra app. Quando l'utente torna, puoi riconnetterti alla rete e consentire all'utente di riprendere la riproduzione del video dallo stesso punto.

Ogni callback consente di eseguire un lavoro specifico appropriato per un determinato cambiamento di stato. Eseguire il lavoro giusto al momento giusto e gestire correttamente le transizioni rende la tua app più solida e performante. Ad esempio, una buona implementazione dei callback del ciclo di vita può aiutare la tua app a evitare quanto segue:

  • Arresto anomalo se l'utente riceve una chiamata o passa a un'altra app mentre utilizza la tua app.
  • Consumare risorse di sistema preziose quando l'utente non lo utilizza attivamente.
  • Perdita dei progressi dell'utente se esce dall'app e vi fa ritorno in un secondo momento.
  • Arresto anomalo o perdita dei progressi dell'utente quando lo schermo ruota tra orientamento orizzontale e verticale.

Questo documento spiega in dettaglio il ciclo di vita dell'attività. Il documento inizia con la descrizione del paradigma del ciclo di vita. Poi, spiega ogni callback: cosa succede internamente durante l'esecuzione e cosa devi implementare durante l'esecuzione.

Viene quindi introdotta brevemente la relazione tra lo stato dell'attività e la vulnerabilità di un processo all'interruzione da parte del sistema. Infine, vengono trattati diversi argomenti relativi alle transizioni tra gli stati di attività.

Per informazioni sulla gestione dei cicli di vita, incluse indicazioni sulle best practice, consulta Ciclo di vita in Jetpack Compose e Salvataggio degli stati dell'interfaccia utente. Per scoprire come progettare un'app solida e di qualità di produzione utilizzando le attività in combinazione con i componenti dell'architettura, consulta la Guida all'architettura dell'app.

Concetti del ciclo di vita dell'attività

Per spostarsi tra le transizioni delle fasi del ciclo di vita dell'attività, la classe Activity fornisce un insieme di base di sei callback: onCreate, onStart, onResume, onPause, onStop e onDestroy. Il sistema richiama ognuna di queste callback quando l'attività entra in un nuovo stato.

La figura 1 mostra una rappresentazione visiva di questo paradigma.

Figura 1. Un'illustrazione semplificata del ciclo di vita dell'attività.

Quando l'utente inizia a uscire dall'attività, il sistema chiama i metodi per smantellare l'attività. In alcuni casi, l'attività viene smontata solo parzialmente e rimane in memoria, ad esempio quando l'utente passa a un'altra app. In questi casi, l'attività può comunque tornare in primo piano.

Se l'utente torna all'attività, questa riprende da dove l'utente l'aveva interrotta. Con alcune eccezioni, le app non possono avviare attività quando vengono eseguite in background.

La probabilità che il sistema termini un determinato processo, insieme alle attività al suo interno, dipende dallo stato dell'attività in quel momento. Per saperne di più sul rapporto tra stato e vulnerabilità all'espulsione, consulta la sezione relativa allo stato dell'attività e all'espulsione dalla memoria.

A seconda della complessità dell'attività, probabilmente non devi implementare tutti i metodi del ciclo di vita. Tuttavia, è importante che tu comprenda ciascuno di questi intent e implementi quelli che fanno sì che la tua app si comporti nel modo in cui gli utenti si aspettano.

Composizione e ciclo di vita

In Compose, evita di inserire la logica di business o la configurazione manuale dell'observer direttamente all'interno dei callback delle attività come onStart o onResume. Utilizza invece effetti e osservatori sensibili al ciclo di vita e allo stato, che si allineano automaticamente alla presenza dell'interfaccia utente sullo schermo.

  • Raccolta basata sul ciclo di vita: utilizza collectAsStateWithLifecycle per utilizzare i flussi da ViewModel. Questa API inizia automaticamente la raccolta quando la UI entra nello stato Started e si interrompe quando passa in background, evitando un consumo non necessario di risorse. Dopo aver raccolto il flusso come stato, puoi utilizzare LifecycleEffects per eseguire il codice quando si verifica un evento del ciclo di vita.
  • Flusso della logica: utilizzando queste API, la UI reagisce allo stato del ciclo di vita in modo naturale tramite l'albero di composizione, garantendo che la logica di business venga eseguita solo quando l'utente interagisce attivamente con il componente.

Per saperne di più su Compose e sul ciclo di vita, consulta Ciclo di vita in Jetpack Compose.

Callback del ciclo di vita

Questa sezione fornisce informazioni concettuali e di implementazione sui metodi di callback utilizzati durante il ciclo di vita dell'attività.

Alcune azioni appartengono ai metodi del ciclo di vita dell'attività. Tuttavia, inserisci il codice che implementa le azioni di un componente dipendente nel componente, anziché nel metodo del ciclo di vita dell'attività. Per farlo, devi rendere il componente dipendente consapevole del ciclo di vita. Per scoprire come rendere i componenti dipendenti compatibili con il ciclo di vita, consulta Ciclo di vita in Jetpack Compose.

onCreate

Devi implementare questo callback, che viene attivato quando il sistema crea per la prima volta l'attività. Al momento della creazione, l'attività entra nello stato Creata. Nel metodo onCreate, esegui la logica di avvio di base dell'applicazione che si verifica solo una volta per l'intera durata dell'attività.

Ad esempio, l'implementazione di onCreate potrebbe associare i dati agli elenchi, associare l'attività a un ViewModel e creare un'istanza di alcune variabili di ambito della classe. Questo metodo riceve il parametro savedInstanceState, che è un oggetto Bundle contenente lo stato dell'attività salvato in precedenza. Se l'attività non è mai esistita prima, il valore dell'oggetto Bundle è null.

Se hai un componente sensibile al ciclo di vita collegato al ciclo di vita della tua attività, riceve l'evento ON_CREATE. Il metodo annotato con @OnLifecycleEvent viene chiamato in modo che il componente sensibile al ciclo di vita possa eseguire il codice di configurazione necessario per lo stato creato.

Il seguente esempio mostra come integrare un composable Text in un'attività di base:

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

La tua attività non rimane nello stato Creato. Al termine dell'esecuzione del metodo onCreate, l'attività entra nello stato Started e il sistema chiama i metodi onStart e onResume in rapida successione.

onStart

Quando l'attività entra nello stato Avviata, il sistema richiama onStart. Questa chiamata rende l'attività visibile all'utente mentre l'app si prepara a portare l'attività in primo piano e renderla interattiva. Ad esempio, in questo metodo viene inizializzato il codice che gestisce la UI.

Quando l'attività passa allo stato Avviata, qualsiasi componente sensibile al ciclo di vita collegato al ciclo di vita dell'attività riceve l'evento ON_START.

Il metodo onStart viene completato rapidamente e, come per lo stato Created, l'attività non rimane nello stato Started. Al termine di questo callback, l'attività entra nello stato Resumed e il sistema richiama il metodo onResume.

onResume

Quando l'attività entra nello stato Resumed, viene portata in primo piano e il sistema richiama il callback onResume. Questo è lo stato in cui l'app interagisce con l'utente. L'app rimane in questo stato finché non si verifica un evento che toglie il focus dall'app, ad esempio il dispositivo riceve una chiamata, l'utente passa a un'altra Activity o lo schermo del dispositivo si spegne.

Quando l'attività passa allo stato Ripresa, qualsiasi componente sensibile al ciclo di vita collegato al ciclo di vita dell'attività riceve l'evento ON_RESUME. È qui che i componenti del ciclo di vita possono attivare qualsiasi funzionalità che deve essere eseguita mentre il componente è visibile e in primo piano, ad esempio l'avvio di un'anteprima della videocamera.

Quando si verifica un evento interruttivo, l'attività entra nello stato In pausa e il sistema richiama il callback onPause.

Se l'attività torna allo stato Ripresa dallo stato In pausa, il sistema chiama di nuovo il metodo onResume. Per questo motivo, implementa onResume per inizializzare i componenti che rilasci durante onPause ed eseguire qualsiasi altra inizializzazione che deve verificarsi ogni volta che l'attività entra nello stato Resumed.

Ecco un esempio di componente sensibile al ciclo di vita che accede alla videocamera quando il componente riceve l'evento ON_RESUME:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

Il codice precedente inizializza la videocamera una volta che LifecycleObserver riceve l'evento ON_RESUME. In modalità multi-finestra, tuttavia, la tua attività potrebbe essere completamente visibile anche quando è in stato di pausa. Ad esempio, quando l'app è in modalità multi-finestra e l'utente tocca la finestra che non contiene la tua attività, quest'ultima passa allo stato Sospesa.

Se vuoi che la videocamera sia attiva solo quando l'app è ripresa (visibile e attiva in primo piano), inizializza la videocamera dopo l'evento ON_RESUME mostrato in precedenza. Se vuoi mantenere la videocamera attiva mentre l'attività è in pausa ma visibile, ad esempio in modalità multi-finestra, inizializza la videocamera dopo l'evento ON_START.

Tuttavia, se la videocamera è attiva mentre l'attività è in pausa, potrebbe negare l'accesso alla videocamera a un'altra app ripresa in modalità multi-finestra. A volte è necessario mantenere attiva la videocamera mentre l'attività è in pausa, ma ciò potrebbe peggiorare l'esperienza utente complessiva.

Per questo motivo, pensa attentamente a quale punto del ciclo di vita è più opportuno assumere il controllo delle risorse di sistema condivise nel contesto della modalità multi-finestra. Per saperne di più sul supporto della modalità multi-finestra, vedi Supportare la modalità multi-finestra.

Indipendentemente dall'evento di accumulo in cui scegli di eseguire un'operazione di inizializzazione, assicurati di utilizzare l'evento del ciclo di vita corrispondente per rilasciare la risorsa. Se inizializzi qualcosa dopo l'evento ON_START, rilascialo o termina dopo l'evento ON_STOP. Se inizializzi dopo l'evento ON_RESUME, rilascia dopo l'evento ON_PAUSE.

Lo snippet di codice precedente inserisce il codice di inizializzazione della videocamera in un componente compatibile con il ciclo di vita. Puoi invece inserire questo codice direttamente nei callback del ciclo di vita dell'attività, come onStart e onStop, ma non lo consigliamo. L'aggiunta di questa logica a un componente indipendente e consapevole del ciclo di vita ti consente di riutilizzare il componente in più attività senza dover duplicare il codice. Per scoprire come creare un componente compatibile con il ciclo di vita, consulta Ciclo di vita in Jetpack Compose.

onPause

Il sistema chiama questo metodo come prima indicazione che l'utente sta abbandonando l'attività, anche se non sempre significa che l'attività viene eliminata. Indica che l'attività non è più in primo piano, ma è ancora visibile se l'utente è in modalità multi-finestra. Ci sono diversi motivi per cui un'attività potrebbe entrare in questo stato:

  • Un evento che interrompe l'esecuzione dell'app, come descritto nella sezione relativa al callback onResume, mette in pausa l'attività corrente. Questo è il caso più comune.
  • In modalità multi-finestra, solo un'app è selezionata alla volta e il sistema mette in pausa tutte le altre app.
  • L'apertura di una nuova attività semitrasparente, ad esempio una finestra di dialogo, mette in pausa l'attività che copre. Finché l'attività è parzialmente visibile ma non in primo piano, rimane in pausa.

Quando un'attività passa allo stato Paused, qualsiasi componente sensibile al ciclo di vita collegato al ciclo di vita dell'attività riceve l'evento ON_PAUSE. È qui che i componenti del ciclo di vita possono interrompere qualsiasi funzionalità che non deve essere eseguita mentre il componente non è in primo piano, ad esempio l'interruzione dell'anteprima di una videocamera.

Utilizza il metodo onPause per mettere in pausa o modificare le operazioni che non possono continuare o che potrebbero continuare in moderazione mentre Activity è nello stato In pausa e che prevedi di riprendere a breve.

Puoi anche utilizzare il metodo onPause per rilasciare risorse di sistema, handle per sensori (come il GPS) o qualsiasi risorsa che influisce sulla durata della batteria mentre l'attività è in pausa e l'utente non ne ha bisogno.

Tuttavia, come indicato nella sezione relativa a onResume, un'attività in pausa potrebbe essere ancora completamente visibile se l'app è in modalità multi-finestra. Valuta la possibilità di utilizzare onStop anziché onPause per rilasciare o modificare completamente le risorse e le operazioni correlate all'interfaccia utente per supportare meglio la modalità multi-finestra.

Il seguente esempio di LifecycleObserver che reagisce all'evento ON_PAUSE è la controparte dell'esempio di evento ON_RESUME precedente, che rilascia la videocamera che si inizializza dopo la ricezione dell'evento ON_RESUME:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

Questo esempio inserisce il codice di rilascio della videocamera dopo che l'evento ON_PAUSE è stato ricevuto da LifecycleObserver.

L'esecuzione di onPause è molto breve e non offre necessariamente tempo sufficiente per eseguire le operazioni di salvataggio. Per questo motivo, non utilizzare onPause per salvare dati di applicazioni o utenti, effettuare chiamate di rete o eseguire transazioni di database. Queste operazioni potrebbero non essere completate prima del termine del metodo.

Esegui invece le operazioni di arresto con carico elevato durante onStop. Per saperne di più sulle operazioni adatte da eseguire durante onStop, consulta la sezione successiva. Per saperne di più sul salvataggio dei dati, consulta la sezione relativa al salvataggio e al ripristino dello stato.

Il completamento del metodo onPause non significa che l'attività esce dallo stato In pausa. L'attività rimane in questo stato finché non riprende o non diventa completamente invisibile all'utente. Se l'attività riprende, il sistema richiama di nuovo il callback onResume.

Se l'attività passa dallo stato Paused (In pausa) allo stato Resumed (Ripresa), il sistema mantiene l'istanza Activity residente in memoria, richiamandola quando il sistema richiama onResume. In questo scenario, non è necessario reinizializzare i componenti creati durante uno dei metodi di callback che portano allo stato Resumed. Se l'attività diventa completamente invisibile, il sistema chiama onStop.

onStop

Quando l'attività non è più visibile all'utente, entra nello stato Interrotto e il sistema richiama il callback onStop. Ciò può verificarsi quando un'attività appena avviata copre l'intero schermo. Il sistema chiama anche onStop quando l'attività termina l'esecuzione e sta per essere terminata.

Quando l'attività passa allo stato Interrotto, qualsiasi componente sensibile al ciclo di vita collegato al ciclo di vita dell'attività riceve l'evento ON_STOP. È qui che i componenti del ciclo di vita possono interrompere qualsiasi funzionalità che non deve essere eseguita mentre il componente non è visibile sullo schermo.

Nel metodo onStop, rilascia o regola le risorse non necessarie mentre l'app non è visibile all'utente. Ad esempio, l'app potrebbe mettere in pausa le animazioni o passare da aggiornamenti della posizione granulari ad aggiornamenti della posizione approssimativi. L'utilizzo di onStop anziché di onPause significa che il lavoro correlato all'interfaccia utente continua, anche quando l'utente visualizza la tua attività in modalità multi-finestra.

Inoltre, utilizza onStop per eseguire operazioni di spegnimento che richiedono un utilizzo relativamente elevato della CPU. Ad esempio, se non riesci a trovare un momento migliore per salvare le informazioni in un database, potresti farlo durante onStop. L'esempio seguente mostra un'implementazione di onStop che salva i contenuti di una nota bozza in uno spazio di archiviazione permanente:

override fun onStop() {
    super.onStop()

    // Delegate the save operation to the ViewModel, which handles the
    // background thread operations (e.g., using Kotlin Coroutines and Room).
    noteViewModel.saveDraft()
}

Quando l'attività entra nello stato Interrotto, l'oggetto Activity viene mantenuto in memoria: mantiene tutte le informazioni su stato e membri, ma non è collegato al gestore finestre. Quando l'attività riprende, vengono richiamate queste informazioni.

Dallo stato Arrestato, l'attività torna a interagire con l'utente oppure termina l'esecuzione e scompare. Se l'attività viene ripristinata, il sistema richiama onRestart. Se l'esecuzione di Activity è terminata, il sistema chiama onDestroy.

onDestroy

onDestroy viene chiamato prima che l'attività venga eliminata. Il sistema richiama questo callback per uno dei due motivi seguenti:

  1. L'attività sta per terminare perché l'utente l'ha chiusa completamente o perché è stato chiamato finish.
  2. Il sistema sta distruggendo temporaneamente l'attività a causa di una modifica alla configurazione, ad esempio la rotazione del dispositivo o l'inserimento della modalità multi-finestra.

Quando l'attività passa allo stato di distruzione, qualsiasi componente consapevole del ciclo di vita associato al ciclo di vita dell'attività riceve l'evento ON_DESTROY. È qui che i componenti del ciclo di vita possono liberare spazio per tutto ciò che devono prima che Activity venga distrutto.

Anziché inserire la logica in Activity per determinare il motivo per cui viene eliminato, utilizza un oggetto ViewModel per contenere i dati della visualizzazione pertinenti per Activity. Se Activity viene ricreato a causa di una modifica alla configurazione, ViewModel non deve fare nulla, poiché viene conservato e fornito alla successiva istanza Activity.

Se Activity non viene ricreato, ViewModel chiama il metodo onCleared, in cui può liberare spazio dai dati necessari prima di essere eliminato. Puoi distinguere questi due scenari con il metodo isFinishing.

Se l'attività sta per terminare, onDestroy è l'ultimo callback del ciclo di vita che riceve. Se onDestroy viene chiamato in seguito a una modifica della configurazione, il sistema crea immediatamente una nuova istanza di attività e poi chiama onCreate su questa nuova istanza nella nuova configurazione.

Il callback onDestroy rilascia tutte le risorse non rilasciate dai callback precedenti, ad esempio onStop.

Stato dell'attività ed espulsione dalla memoria

Il sistema termina i processi quando deve liberare RAM. La probabilità che il sistema termini un determinato processo dipende dallo stato del processo in quel momento. Lo stato del processo, a sua volta, dipende dallo stato dell'attività in esecuzione nel processo. La tabella 1 mostra le correlazioni tra lo stato del processo, lo stato dell'attività e la probabilità che il sistema termini il processo. Questa tabella si applica solo se un processo non esegue altri tipi di componenti dell'applicazione.

Probabilità di essere ucciso

Stato elaborazione

Stato finale dell'attività

Minima

In primo piano (con focus o in procinto di ottenerlo)

Ripristinato

Bassa

Visibile (nessuna selezione)

Avviato/In pausa

Superiore

Sfondo (invisibile)

Interrotta

Massima

Vuoto

Eliminata

Tabella 1. Relazione tra il ciclo di vita del processo e lo stato dell'attività.

Il sistema non termina mai un'attività direttamente per liberare memoria. Invece, termina il processo in cui viene eseguita l'attività, distruggendo non solo l'attività, ma anche tutto il resto in esecuzione nel processo. Per scoprire come conservare e ripristinare lo stato dell'interfaccia utente dell'attività quando si verifica l'interruzione del processo avviata dal sistema, consulta la sezione relativa al salvataggio e al ripristino dello stato.

L'utente può anche terminare un processo utilizzando Application Manager, in Impostazioni, per terminare l'app corrispondente.

Per saperne di più sui processi, consulta la panoramica di processi e thread.

Salvataggio e ripristino dello stato temporaneo della UI

Un utente si aspetta che lo stato dell'interfaccia utente di un'attività rimanga invariato durante una modifica della configurazione, ad esempio la rotazione o il passaggio alla modalità multi-finestra. Tuttavia, il sistema distrugge l'attività per impostazione predefinita quando si verifica una modifica di configurazione, eliminando qualsiasi stato dell'interfaccia utente memorizzato nell'istanza dell'attività.

Allo stesso modo, un utente si aspetta che lo stato dell'interfaccia utente rimanga invariato se passa temporaneamente dalla tua app a un'altra e poi torna alla tua app in un secondo momento. Tuttavia, il sistema può eliminare il processo dell'applicazione mentre l'utente non è presente e la tua attività è interrotta.

Quando i vincoli di sistema eliminano l'Activity, conserva lo stato dell'interfaccia utente temporanea dell'utente utilizzando una combinazione di ViewModel (per la logica di business complessa e lo stato dello schermo), l'API Jetpack Compose rememberSaveable (per lo stato dell'interfaccia utente leggero) e/o l'archiviazione locale. Per scoprire di più sulle aspettative degli utenti rispetto al comportamento del sistema e su come conservare al meglio i dati complessi sullo stato dell'interfaccia utente in caso di attività e interruzione del processo avviate dal sistema, consulta Salvare gli stati dell'interfaccia utente.

rememberSaveable sopravvive automaticamente sia alle modifiche alla configurazione sia all'interruzione del processo avviata dal sistema raggruppando lo stato in background, fornendo un'esperienza senza interruzioni senza la necessità di boilerplate a livello di attività.

Stato istanza

Esistono alcuni scenari in cui l'attività viene eliminata a causa del normale comportamento dell'app, ad esempio quando l'utente preme il pulsante Indietro o l'attività segnala la propria eliminazione chiamando il metodo finish.

Quando l'attività viene eliminata perché l'utente preme Indietro o perché l'attività termina autonomamente, sia il concetto di sistema che quello dell'utente di quell'istanza di Activity scompare per sempre. In questi scenari, l'aspettativa dell'utente corrisponde al comportamento del sistema e non devi fare altro.

Tuttavia, se il sistema distrugge l'attività a causa di vincoli di sistema (ad esempio una modifica alla configurazione o una pressione sulla memoria), anche se l'istanza Activity effettiva non è più presente, il sistema ricorda che esisteva. Se l'utente tenta di tornare all'attività, il sistema crea una nuova istanza dell'attività utilizzando un insieme di dati salvati che descrivono lo stato dell'attività quando è stata eliminata.

I dati salvati che il sistema utilizza per ripristinare lo stato precedente sono chiamati stato dell'istanza. Sotto il cofano, è una raccolta di coppie chiave-valore. Per impostazione predefinita, il sistema utilizza lo stato dell'istanza per salvare le informazioni di base sul layout dell'interfaccia utente, ad esempio l'input di testo dell'utente o le posizioni di scorrimento.

Per sfruttare questo comportamento del sistema, utilizza rememberSaveable. Se l'istanza dell'attività viene eliminata e ricreata, qualsiasi stato dell'interfaccia utente racchiuso in rememberSaveable viene ripristinato automaticamente, senza che tu debba aggiungere codice a livello di attività.

Tuttavia, la tua attività probabilmente avrà informazioni sullo stato più complesse che vorresti ripristinare, come dati utente, risposte di rete o variabili membro che monitorano i progressi dell'utente. Il meccanismo di stato dell'istanza (e, per estensione, rememberSaveable) non è adatto a conservare una quantità di dati superiore a una quantità banale, perché richiede la serializzazione sul thread principale e consuma la memoria del processo di sistema.

Per conservare una quantità di dati superiore a una quantità molto piccola, adotta un approccio combinato utilizzando l'archiviazione locale permanente, la classe ViewModel e l'innalzamento dello stato di Compose, come descritto in Salvare gli stati dell'interfaccia utente.

Salva lo stato dell'interfaccia utente semplice e leggera utilizzando rememberSaveable

Quando l'attività inizia a interrompersi, il sistema si prepara a salvare le informazioni sullo stato in un bundle di stato dell'istanza. Per sfruttare questo comportamento del sistema, utilizza rememberSaveable direttamente all'interno delle funzioni componibili. rememberSaveable salva e ripristina automaticamente lo stato dell'interfaccia utente temporanea, ad esempio l'input di testo dell'utente o le posizioni di scorrimento, durante la ricreazione dell'attività.

Per salvare informazioni di stato personalizzate e leggere (come i progressi di un utente in un gioco), dichiara lo stato utilizzando rememberSaveable. Il framework Compose gestisce la serializzazione nel bundle dello stato dell'istanza in modo trasparente:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

Per salvare dati persistenti, come le preferenze dell'utente o i dati per un database, cogli le opportunità appropriate quando la tua attività è in primo piano. Se non si presenta un'opportunità di questo tipo, salva i dati permanenti durante il metodo onStop.

Ripristina lo stato dell'interfaccia utente dell'attività utilizzando lo stato dell'istanza salvato

Quando la tua attività viene ricreata dopo essere stata distrutta in precedenza, il ripristino dello stato è automatico. Quando utilizzi rememberSaveable, non devi scrivere alcuna logica di ripristino esplicita, controllare i bundle nulli o eseguire l'override dei callback delle attività. Il codice che inizializza e salva lo stato lo ripristina senza problemi quando l'attività torna:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

Attività e navigazione

È probabile che un'app passi da una schermata all'altra molte volte durante il suo ciclo di vita, ad esempio quando l'utente tocca il pulsante Indietro del dispositivo o seleziona una nuova destinazione. Le moderne app per Android in genere utilizzano un'architettura a singola attività. Anziché avviare una nuova Activity per ogni schermata, la tua app ospita una singola Activity e utilizza il componente Navigation per sostituire le schermate componibili all'interno di questa attività.

Per scoprire come implementare la navigazione moderna, basata su Compose, consulta la guida alla libreria Navigation 3 di Jetpack Compose.

Avviare un'attività da un'altra

Un'attività potrebbe dover avviare un'altra attività a un certo punto. Questa necessità si presenta, ad esempio, quando un'app deve passare dalla schermata corrente a una nuova.

A seconda che la tua attività voglia ricevere un risultato dalla nuova attività che sta per iniziare, avvia la nuova attività utilizzando il metodo startActivity o il metodo startActivityForResult. In entrambi i casi, passi un oggetto Intent.

L'oggetto Intent specifica l'attività esatta che vuoi avviare o descrive il tipo di azione che vuoi eseguire. Il sistema seleziona l'attività più adatta a te, che può anche provenire da un'applicazione diversa. Un oggetto Intent può anche contenere piccole quantità di dati da utilizzare nell'attività che viene avviata. Per saperne di più sulla classe Intent, consulta Intent e filtri per intent.

startActivity

Se l'attività appena avviata non deve restituire un risultato, l'attività corrente può avviarla chiamando il metodo startActivity.

Quando lavori all'interno della tua applicazione, spesso devi semplicemente avviare un'attività nota. Ad esempio, il seguente snippet di codice mostra come avviare un'attività chiamata SignInActivity.

val context = LocalContext.current

Button(onClick = {
    val intent = Intent(context, SignInActivity::class.java)
    context.startActivity(intent)
}) {
    Text("Sign In")
}

Avvio di attività esterne

Mentre la navigazione interna dell'app viene gestita da Navigation, il tuo Activity dovrà occasionalmente avviare altre attività. Di solito ciò accade quando vuoi utilizzare un'app esterna per eseguire un'azione specifica, come aprire un browser web, inviare un'email o scattare una foto.

Per farlo, utilizzi un oggetto Intent per descrivere il tipo di azione che vuoi eseguire e il sistema avvia l'attività appropriata da un'altra applicazione.

Ad esempio, se vuoi consentire all'utente di inviare un messaggio email, puoi creare il seguente intent:

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Se devi avviare un'attività esterna e ricevere un risultato (ad esempio chiedere all'app fotocamera di scattare una foto e restituire l'immagine), utilizza le moderne Activity API result anziché il callback startActivityForResult ritirato.

Coordinamento delle attività

Quando un'attività ne avvia un'altra, entrambe subiscono transizioni del ciclo di vita. La prima attività smette di funzionare e passa allo stato In pausa o Interrotto, mentre viene creata l'altra attività. Nel caso in cui queste attività condividano dati salvati su disco o altrove, è importante capire che la prima attività non viene interrotta completamente prima della creazione della seconda. Il processo di avvio del secondo si sovrappone a quello di interruzione del primo.

L'ordine dei callback del ciclo di vita è ben definito, in particolare quando le due attività si trovano nello stesso processo, ovvero nella stessa app, e una avvia l'altra. Ecco l'ordine delle operazioni che si verificano quando l'attività A avvia l'attività B:

  1. Viene eseguito il metodo onPause di Activity A.
  2. I metodi onCreate, onStart e onResume dell'attività B vengono eseguiti in sequenza. L'attività B ora è in primo piano.
  3. Se l'attività A non è più visibile sullo schermo, viene eseguito il relativo metodo onStop.

Questa sequenza di callback del ciclo di vita consente di gestire la transizione delle informazioni da un'attività all'altra.

Risorse aggiuntive

Per saperne di più sul ciclo di vita dell'attività, consulta le seguenti risorse aggiuntive:

Visualizza contenuti