Il ciclo di vita dell'attività

Quando un utente naviga all'interno, uscire e tornare alla tua app, Transizione di Activity istanze nella tua app tramite stati diversi nel loro ciclo di vita. La classe Activity prevede una serie di richiamate che comunicano all'attività quando uno stato cambia o che sistema sta creando, arrestando o riprendendo un'attività o distruggendo il processo in cui risiede l'attività.

Nei metodi di callback del ciclo di vita, puoi dichiarare in che modo si comporta quando l'utente esce dall'attività e vi rientra. Ad esempio, se stai creando un video player in streaming, potresti mettere in pausa il video connessione di rete quando l'utente passa a un'altra app. Quando l'utente ritorna, puoi riconnetterti alla rete e consentire all'utente di riprendere la visione del video lo stesso punto.

Ogni callback ti consente di eseguire operazioni specifiche appropriato per un determinato cambiamento di stato. Svolgere il lavoro giusto con la giusta e gestire correttamente le transizioni rendono la tua app più solida e performante. Ad esempio, una buona implementazione dei callback del ciclo di vita può aiutare la tua app evita quanto segue:

  • Arresto anomalo se l'utente riceve una chiamata o passa a un'altra chiamata mentre la utilizzi.
  • Consumo di preziose risorse di sistema quando l'utente non sta attivamente utilizzandolo.
  • Perdere i progressi dell'utente se esce dall'app e torna a 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 delle attività. Il documento inizia descrivendo il paradigma del ciclo di vita. A seguire, vengono spiegati tutti i richiami: cosa succede internamente durante l'esecuzione e cosa è necessario implementare durante questo processo.

Quindi introduce brevemente la relazione tra attività e la vulnerabilità di un processo all'eliminazione da parte del sistema. Infine, tratta diversi argomenti relativi alle transizioni gli stati dell'attività.

Per informazioni sulla gestione dei cicli di vita, incluse indicazioni sulla best practice, consulta Gestione dei cicli di vita con componenti sensibili al ciclo di vita e Salva stati dell'interfaccia utente. Per imparare a progettare un'app solida e di qualità per la produzione utilizzando le attività in combinazione con i componenti dell'architettura, vedi Guida all'architettura delle app.

Concetti sul ciclo di vita dell'attività

Per navigare nelle transizioni tra le fasi del ciclo di vita dell'attività, La classe Activity prevede un insieme principale di sei callback: onCreate(), onStart(), onResume(), onPause(), onStop() e onDestroy(). Il sistema richiama ciascuno di questi callback quando l'attività entra in un nuovo stato.

La Figura 1 presenta una rappresentazione visiva di questo paradigma.

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

Quando l'utente inizia ad abbandonare l'attività, il sistema chiama dei metodi per smantellare l'attività. In alcuni casi, l'attività è solo parzialmente smantellato e ancora oggi in memoria, ad esempio quando l'utente passa un'altra app. In questi casi, l'attività può comunque tornare in primo piano.

Se l'utente torna all'attività, riprenderà dal punto in cui l'utente era stato interrotto. Con alcune eccezioni, le app sono limitato da avviare attività in esecuzione in background.

La probabilità che il sistema l'interruzione di un determinato processo, insieme alle attività in esso contenute, dipende dallo stato dell'attività in quel momento. Per ulteriori informazioni sulla relazione tra stato e la vulnerabilità all'esclusione, consulta la sezione relativa allo stato dell'attività e all'espulsione dalla memoria.

A seconda della complessità della tua attività, probabilmente non c'è bisogno a implementare tutti i metodi del ciclo di vita. Tuttavia, è importante che tu capire come funzionano e implementare quelle che consentono alla tua app di comportarsi come si aspettano gli utenti.

Callback del ciclo di vita

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

Alcune azioni appartengono ai metodi del ciclo di vita delle attività. Tuttavia, inserisci il codice che implementa le azioni di un componente dipendente anziché il metodo del ciclo di vita delle attività. Per farlo, devi avere per rendere il componente dipendente sensibile al ciclo di vita. Per scoprire come realizzare e sensibili al ciclo di vita dei componenti dipendenti, consulta Gestione dei cicli di vita con componenti sensibili al ciclo di vita.

onCreate()

Devi implementare questo callback, che si attiva quando il sistema crea per la prima volta il attività. Al momento della creazione, l'attività passa allo stato Creata. In onCreate() esegui una logica di avvio dell'applicazione di base, avviene una sola volta durante l'intera durata dell'attività.

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

Se hai un componente sensibile al ciclo di vita collegato al ciclo di vita la tua attività, riceve ON_CREATE . Il metodo annotato con @OnLifecycleEvent viene chiamato in modo che sia sensibile al ciclo di vita può eseguire qualsiasi codice di configurazione necessario per lo stato di creazione.

Il seguente esempio del metodo onCreate() mostra la configurazione di base dell'attività, ad esempio la dichiarazione dell'interfaccia utente (definite in un file di layout XML), definendo le variabili membro e configurando parte dell'interfaccia utente. In questo esempio, il file di layout XML trasmette il parametro l'ID risorsa del file R.layout.main_activity setContentView().

Kotlin

lateinit var textView: TextView

// Some transient state for the activity instance.
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState)

    // Recover the instance state.
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity)

    // Initialize member TextView so it is available later.
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState)
}

Java

TextView textView;

// Some transient state for the activity instance.
String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState);

    // Recover the instance state.
    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity);

    // Initialize member TextView so it is available later.
    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState);
}

In alternativa alla definizione del file XML e passarlo a setContentView(), puoi creare nuovi oggetti View nel tuo codice attività e creare un per visualizzare la gerarchia inserendo nuovi oggetti View in un ViewGroup. Puoi quindi utilizzare questo layout passando il parametro principale da ViewGroup a setContentView(). Per ulteriori informazioni sulla creazione di un'interfaccia utente, consulta interfaccia utente.

La tua attività non rimane in Creati stato. Al termine dell'esecuzione del metodo onCreate(), l'attività entra nel campo Iniziata e il sistema chiama onStart() e onResume() di metodi in successione.

onStart()

Quando l'attività passa allo stato Iniziata, il sistema richiama onStart(). Questa chiamata rende l'attività visibile all'utente come l'app si prepara affinché l'attività entri in primo piano e diventi interattiva. Ad esempio, in questo metodo il codice che mantiene l'inizializzazione dell'interfaccia utente.

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

Il metodo onStart() viene completato rapidamente e, come per lo stato Creato, l'attività non rimane nello stato Iniziato. Al termine del callback, l'attività inserisce la Lo stato Riprendi e il sistema richiama il metodo onResume().

onRiprendi()

Quando l'attività passa allo stato Ripresa, l'attività passa in primo piano. il sistema richiama onResume() di Google. Questo è lo stato in cui l'app interagisce con l'utente. L'app rimane in questo stato finché non succede qualcosa a distoglie l'attenzione dall'app, ad esempio il dispositivo che riceve una telefonata, l'utente la navigazione a un'altra attività o lo spegnimento dello schermo del dispositivo.

Quando l'attività passa allo stato Ripresa, qualsiasi componente sensibile al ciclo di vita legato al ciclo di vita dell'attività riceve ON_RESUME . È qui che i componenti del ciclo di vita possono abilitare qualsiasi funzionalità debba essere eseguita il componente sia visibile e in primo piano, ad esempio l'avvio di una fotocamera l'anteprima.

Quando si verifica un evento invasivo, l'attività entra nello stato In pausa e il sistema richiama lo stato Chiamata onPause().

Se l'attività torna a lo stato Ripreso dallo stato In pausa, il sistema richiama nuovamente onResume(). Per questo motivo, implementa onResume() per inizializzare i componenti che rilasci durante onPause() e di eseguire qualsiasi altra inizializzazioni che devono avvenire ogni volta che l'attività entra nel stato.

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

Kotlin

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

Java

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }
    ...
}

Il codice precedente inizializza la fotocamera una volta che LifecycleObserver riceve l'evento ON_RESUME. In modalità multi-finestra, invece, le tue attività potrebbe essere completamente visibile anche quando è nello stato In pausa. Ad esempio, quando l'app è in modalità multi-finestra e l'utente tocca la finestra che non contengono la tua attività, l'attività passa allo stato In pausa.

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

Tuttavia, avere la videocamera mentre l'attività è in pausa potrebbe negare l'accesso alla videocamera a un'altra App ripresa in modalità multi-finestra. A volte è necessario mantenere videocamera attiva mentre la tua attività è in pausa, ma in realtà potrebbe peggiorare la qualità in generale l'esperienza utente.

Per questo motivo, valuta attentamente il punto in cui del loro ciclo di vita è più appropriato assumere il controllo delle risorse il contesto della modalità multi-finestra. Per ulteriori informazioni sul supporto della modalità multi-finestra vedi Supporto multi-finestra.

Indipendentemente dall'evento di compilazione che scegli di eseguire di inizializzazione, assicurati di utilizzare il ciclo di vita corrispondente per rilasciare la risorsa. Se inizializzati qualcosa dopo l'evento ON_START, rilasciarlo o terminarlo dopo il Evento ON_STOP. Se vengono inizializzate dopo l'evento ON_RESUME, rilasciate dopo Evento ON_PAUSE.

Lo snippet di codice precedente inserisce il codice di inizializzazione della fotocamera in una basato sul ciclo di vita. Puoi invece inserire questo codice direttamente nell'attività callback del ciclo di vita, come onStart() e onStop(), ma sconsigliamo di farlo. Aggiunta di questa logica a un componente indipendente che riconosce il ciclo di vita e ti consente di riutilizzarlo in più attività senza dover duplicare il codice. Per scoprire come creare un componente sensibile al ciclo di vita, consulta Gestione dei cicli di vita con componenti sensibili al ciclo di vita.

onPause()

Il sistema chiama questo metodo come prima indicazione che l'utente sta uscendo la tua attività, anche se non sempre significa che questa sia stata distrutta. Indica che l'attività non è più in primo piano, ma è sono ancora visibili se l'utente è in modalità multi-finestra. Esistono diversi motivi per cui un'attività può entrare questo stato:

  • Un evento che interrompe l'esecuzione dell'app, come descritto nella sezione relativa alle il callback onResume() mette in pausa l'attività corrente. Questo è il tipo di comportamento più comune per verificare se è così.
  • In modalità multi-finestra, solo un'app è attiva in qualsiasi momento 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. Purché l'attività è parzialmente visibile ma non a fuoco, rimangono in pausa.

Quando un'attività passa allo stato In pausa, qualsiasi componente sensibile al ciclo di vita legato al ciclo di vita dell'attività riceve Evento ON_PAUSE. È qui che entrano in gioco i componenti del ciclo di vita possono interrompere qualsiasi funzionalità mentre il componente non è in primo piano, ad esempio interrompendo una videocamera l'anteprima.

Utilizza il metodo onPause() per mettere in pausa o regolare le operazioni che non possono continuare o che potrebbero continuare con la moderazione mentre Activity è in stato In pausa e che tu che riprendono a breve.

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

Tuttavia, come citato nella sezione relativa a onResume(), un l'attività potrebbe essere ancora completamente visibile se l'app è in modalità multi-finestra. Potresti usare onStop() anziché onPause() per rilasciare o regolare completamente Risorse e operazioni relative all'interfaccia utente per un supporto migliore della modalità multi-finestra.

Il seguente esempio di LifecycleObserver la reazione all'evento ON_PAUSE è la controparte dell'evento precedente Esempio di evento ON_RESUME, con il rilascio della fotocamera che si inizializza dopo viene ricevuto l'evento ON_RESUME:

Kotlin

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

Java

public class JavaCameraComponent implements LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }
    ...
}

In questo esempio il codice di rilascio della fotocamera viene inserito dopo il LifecycleObserver riceve l'evento ON_PAUSE.

onPause() l'esecuzione è molto breve e non offre necessariamente tempo sufficiente per eseguire le operazioni di salvataggio. Per questo motivo, non usare onPause() per salvare l'applicazione o l'utente effettuare chiamate di rete o eseguire transazioni di database. Un simile funzionamento potrebbe non prima del completamento del metodo.

Esegui invece operazioni di arresto per carichi intensivi durante onStop(). Per ulteriori informazioni sulle operazioni adatte a eseguire onStop(), consulta la sezione successiva. Per ulteriori informazioni sul salvataggio vedi la sezione relativa al salvataggio e al ripristino dello stato.

Completamento del metodo onPause() non significa che l'attività lascia lo stato In pausa. Piuttosto, l'attività rimane in questo stato finché l'attività non riprende o non diventa completamente invisibile all'utente. Se l'attività riprende, il sistema richiama di nuovo il callback onResume().

Se l'attività torna dallo stato In pausa a quello Ripresa, il sistema mantiene l'istanza Activity residente in memoria, richiamando per quell'istanza quando il sistema richiama onResume(). In questo scenario, non è necessario reinizializzare i componenti creati durante metodi di callback che portano allo stato Ripreso. Se l'attività diventa completamente invisibile, il sistema chiama onStop().

onStop()

Quando la tua attività non è più visibile all'utente, inserisce il Arrestato e il sistema richiama il Chiamata onStop(). Questo può verificarsi quando un'attività appena avviata copre l'intero schermo. La il sistema chiama anche onStop() quando l'attività termina e sta per essere interrotta.

Quando l'attività passa allo stato Interrotto, qualsiasi componente sensibile al ciclo di vita legato al ciclo di vita dell'attività riceve Evento ON_STOP. È qui che entrano in gioco i componenti del ciclo di vita possono interrompere qualsiasi funzionalità mentre il componente non è visibile sullo schermo.

Nel metodo onStop(), rilascia o regola e risorse che non sono necessarie quando l'app non è visibile all'utente. Ad esempio, la tua app potrebbe metti in pausa le animazioni o passa dagli aggiornamenti della posizione granulari a quelli meno granulari. Utilizzo onStop() anziché onPause() significa che il lavoro relativo all'interfaccia utente continua anche se l'utente sta visualizzando la tua attività in modalità multi-finestra .

Usa anche onStop() di eseguire operazioni di arresto relativamente ad alta intensità di CPU. Ad esempio, se non puoi trovare un momento migliore per salvare le informazioni in un database, potresti farlo durante onStop(). La l'esempio seguente mostra un'implementazione onStop() che salva i contenuti di un bozza di nota per l'archiviazione permanente:

Kotlin

override fun onStop() {
    // Call the superclass method first.
    super.onStop()

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

Java

@Override
protected void onStop() {
    // Call the superclass method first.
    super.onStop();

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

L'esempio di codice precedente utilizza direttamente SQLite. Tuttavia, ti consigliamo di usare Room, una libreria di persistenza che fornisce un livello di astrazione su SQLite. Per ulteriori informazioni scopri di più sui vantaggi dell'utilizzo di Room e su come implementarla nella tua app vedi il Libreria sulla persistenza della stanza guida.

Quando l'attività passa allo stato Interrotta, Activity l'oggetto viene mantenuto in memoria: conserva tutti gli stati e ma non è collegata a Gestione finestre. Quando l'attività riprendi, richiama queste informazioni.

Non è necessario reinizializzare i componenti creati durante uno dei metodi di callback fino allo stato Ripresa. Il sistema tiene traccia anche delle attività per ogni oggetto View nel layout, quindi se l'utente inserisce del testo in un widget EditText, che i contenuti vengono conservati, pertanto non è necessario salvarli e ripristinarli.

Nota: una volta interrotta l'attività, il sistema potrebbe distruggere il processo che contiene l'attività se il sistema deve recuperare memoria. Anche se il sistema distrugge il processo mentre l'attività viene interrotto, il sistema conserva lo stato dell'elemento View come il testo di un widget EditText, in un Bundle, ossia un blob di coppie chiave/valore, e le ripristina. se l'utente torna all'attività. Per per ulteriori informazioni sul ripristino di un'attività a cui un utente ritorna, consulta le sezione relativa al salvataggio e il ripristino dello stato.

Dallo stato Interrotto, l'attività torna a interagire con utente o l'attività termina e scompare. Se l'attività si verifica il sistema richiama onRestart(). Se l'esecuzione di Activity è terminata, il sistema chiama onDestroy().

onDestroy()

onDestroy() viene chiamato prima di viene eliminata l'attività. Il sistema richiama questo callback per uno dei due motivi:

  1. L'attività è terminata perché l'utente ha ignorato completamente il per via di un'attività finish() in corso ha richiamato l'attività.
  2. Il sistema sta eliminando temporaneamente l'attività a causa di una configurazione come la rotazione del dispositivo o l'attivazione della modalità multi-finestra.

Quando l'attività passa allo stato di eliminazione, qualsiasi componente sensibile al ciclo di vita legato al ciclo di vita dell'attività riceve Evento ON_DESTROY. È qui che entrano in gioco i componenti del ciclo di vita possono eseguire la pulizia Eliminazione di Activity completata.

Invece di inserire la logica in Activity per determinare perché viene distrutta, utilizza un oggetto ViewModel per contenere pertinenti per Activity. Se Activity viene ricreato a causa di una modifica alla configurazione, ViewModel non deve fare nulla perché viene conservato e assegnato alla successiva istanza Activity.

Se Activity non viene ricreato, ViewModel ha onCleared(), in cui può ripulire tutti i dati di cui ha bisogno prima di essere distrutti. Puoi distinguere tra questi due scenari isFinishing().

Se l'attività sta completando, onDestroy() è il callback finale del ciclo di vita l'attività ricevuta. Se onDestroy() viene chiamato come risultato di una configurazione modificata, il sistema crea immediatamente una nuova istanza di attività e quindi chiama onCreate() su quella nuova istanza nella nuova configurazione.

Il callback onDestroy() rilascia tutte le risorse non svincolate in precedenza come onStop().

Stato dell'attività ed espulsione dalla memoria

Il sistema termina i processi quando ha bisogno di liberare RAM. La probabilità che il sistema l'interruzione di un determinato processo dipende dallo stato del processo al momento. Stato del processo, dipende a sua volta dallo stato dell'attività in esecuzione nel processo. La tabella 1 mostra le correlazioni tra stato del processo, 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 uccisi Stato processo Stato attività finale
Minima In primo piano (avere o per concentrarsi) Ripristinato
Bassa Visibile (senza stato attivo) Iniziata/in pausa
Superiore Sfondo (invisibile) Interrotto
Massima Vuoto Eliminata

Tabella 1. Relazione tra ciclo di vita del processo e stato di attività.

Il sistema non interrompe mai direttamente un'attività per liberare memoria. Invece, interrompe il processo in cui viene eseguita l'attività, distruggendo non solo l'attività ma anche tutto ciò che è in esecuzione nel processo. Per scoprire come conservare e ripristinare lo stato dell'interfaccia utente della tua attività quando il processo iniziato dal sistema non si interrompe vedi la sezione relativa al salvataggio e al ripristino dello stato.

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

Per ulteriori informazioni sui processi, vedi Processi e thread Panoramica.

Salvataggio e ripristino dello stato temporaneo della UI

Un utente si aspetta che lo stato UI di un'attività rimanga lo stesso per tutto modifica della configurazione, ad esempio la rotazione o il passaggio alla modalità multi-finestra. Tuttavia, il sistema elimina l'attività per impostazione predefinita quando una configurazione di modifica, cancellando qualsiasi stato della UI memorizzato nell'istanza dell'attività.

Analogamente, un utente si aspetta che lo stato della UI rimanga lo stesso se temporaneamente passare dalla tua app a un'altra app e poi tornare all'app in un secondo momento. Tuttavia, il sistema può eliminare il processo della tua applicazione mentre l'utente è assente e la tua attività viene interrotta.

Quando i vincoli di sistema eliminano l'attività, mantieni lo stato temporaneo dell'interfaccia utente usando una combinazione ViewModel, onSaveInstanceState(), e/o archiviazione locale. Per saperne di più sulle aspettative degli utenti rispetto al sistema e come conservare al meglio i dati complessi sullo stato dell'UI da un'attività avviata dal sistema e dall'elaborazione del suo decesso, vedere Salva gli stati dell'interfaccia utente.

Questa sezione descrive lo stato dell'istanza e come implementare onSaveInstance(), che è un callback dell'attività stessa. Se le tue I dati UI sono leggeri, puoi usare solo onSaveInstance() per mantenere la UI lo stato di tutte le modifiche alla configurazione e la morte dei processi avviati dal sistema. Tuttavia, poiché onSaveInstance() comporta costi di serializzazione/deserializzazione, nella maggior parte dei casi utilizzi sia ViewModel sia onSaveInstance(), descritto in Salva gli stati dell'interfaccia utente.

Nota : per saperne di più sulle modifiche alla configurazione, su come limitare le attività ricreazione, se necessario, e come reagire alle modifiche alla configurazione Visualizza il sistema e Jetpack Compose, dai un'occhiata Pagina Gestisci le modifiche alla configurazione.

Stato istanza

Esistono alcuni scenari in cui la tua attività viene eliminata a causa di una normale app comportamento dell'utente, ad esempio quando l'utente preme il pulsante Indietro o la tua attività automaticamente la sua distruzione richiamando il finish() .

Quando l'attività viene eliminata perché l'utente preme Indietro o l'attività termina da sola, il concetto di sistema che l'istanza Activity è stata rimossa per sempre. In queste scenari, le aspettative dell'utente corrispondono al comportamento del sistema e tu non non devi fare altro.

Tuttavia, se il sistema elimina l'attività a causa di vincoli di sistema (come alla configurazione o alla pressione della memoria), sebbene l'effettiva Activity scompare, il sistema ricorda che esisteva. Se l'utente tenta di tornando all'attività, il sistema crea una nuova istanza attività utilizzando un insieme di dati salvati che descrivono lo stato dell'attività quando è stato distrutto.

I dati salvati che il sistema utilizza per ripristinare precedente è chiamato stato istanza. È una raccolta coppie chiave-valore archiviate in un oggetto Bundle. Per impostazione predefinita, utilizza lo stato dell'istanza Bundle per salvare le informazioni su ogni oggetto View nel layout delle attività, ad esempio il valore di testo inserito in un Widget EditText.

Quindi, se l'istanza dell'attività viene eliminata e ricreata, lo stato del layout è ripristinato allo stato precedente senza necessità di codice. Tuttavia, potrebbe avere più informazioni sullo stato che vorresti ripristinare, ad esempio che tengono traccia dell'avanzamento dell'utente nell'attività.

Nota : per consentire al sistema Android di ripristinare lo stato di tutte le visualizzazioni della tua attività, ciascuna di esse deve avere un ID univoco, fornito l'attributo android:id.

Un oggetto Bundle non è appropriato per conservare più di una trascurabile, perché richiede la serializzazione sul thread principale e consuma dei processi di sistema. Per conservare più di una piccola quantità di dati, adottare un approccio combinato alla conservazione dei dati, usando spazio di archiviazione, il metodo onSaveInstanceState() e ViewModel corso, come descritto in Salva gli stati dell'interfaccia utente.

Salva stato UI semplice e leggero utilizzando onSaveInstanceState()

Quando l'attività inizia a interrompersi, il sistema chiama la onSaveInstanceState() in modo che la tua attività possa salvare le informazioni sullo stato in uno stato di istanza gruppo. L'implementazione predefinita di questo metodo salva informazioni sullo stato della gerarchia delle visualizzazioni dell'attività, ad esempio testo in un widget EditText o la posizione di scorrimento di Widget ListView.

Per salvare ulteriori informazioni sullo stato dell'istanza per la tua attività, esegui l'override onSaveInstanceState() e aggiungi coppie chiave-valore all'oggetto Bundle salvato nel caso in cui l'attività venga eliminata inaspettatamente. Quando esegui l'override onSaveInstanceState(), devi chiamare l'implementazione della superclass se vuoi che l'implementazione predefinita salvi lo stato della gerarchia delle viste. Ciò è mostrato nell'esempio seguente:

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game state.
    outState?.run {
        putInt(STATE_SCORE, currentScore)
        putInt(STATE_LEVEL, currentLevel)
    }

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(outState)
}

companion object {
    val STATE_SCORE = "playerScore"
    val STATE_LEVEL = "playerLevel"
}

Java

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state.
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(savedInstanceState);
}

Nota: onSaveInstanceState() non è chiamato quando l'utente chiude esplicitamente l'attività o, in altri casi, quando finish() è stato chiamato.

Per salvare dati permanenti, ad esempio le preferenze utente o i dati per un database, cogliere le opportunità appropriate quando la tua attività è in primo piano. Se non si presenta questa opportunità, salva i dati persistenti durante onStop().

Ripristina lo stato della UI dell'attività utilizzando lo stato dell'istanza salvato

Quando la tua attività viene ricreata dopo essere stata eliminata in precedenza, Puoi recuperare lo stato dell'istanza salvata da Bundle dal sistema alla tua attività. Entrambi i campi onCreate() e onRestoreInstanceState() ricevono lo stesso Bundle che contiene informazioni sullo stato dell'istanza.

Poiché il metodo onCreate() è chiamata se il sistema sta creando una nuova istanza dell'attività o se ne crei di nuovo uno precedente, devi verificare se lo stato Bundle è nullo prima di provare a leggerlo. Se è null, il sistema è la creazione di una nuova istanza dell'attività, invece di ripristinare quella precedente che era stata distrutta.

Il seguente snippet di codice mostra come ripristinare dati sullo stato in onCreate():

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        with(savedInstanceState) {
            // Restore value of members from saved state.
            currentScore = getInt(STATE_SCORE)
            currentLevel = getInt(STATE_LEVEL)
        }
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        // Restore value of members from saved state.
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Invece di ripristinare lo stato durante onCreate(), puoi scegliere di implementare onRestoreInstanceState(), che il sistema chiama dopo il onStart(). Il sistema chiama onRestoreInstanceState() solo se esiste uno stato salvato da ripristinare, quindi non occorre verificare se Bundle è nullo.

Kotlin

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instance.
    savedInstanceState?.run {
        currentScore = getInt(STATE_SCORE)
        currentLevel = getInt(STATE_LEVEL)
    }
}

Java

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance.
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Attenzione: chiama sempre l'implementazione superclass onRestoreInstanceState() in modo che l'implementazione predefinita possa ripristinare lo stato della gerarchia delle viste.

Spostarsi tra le attività

È probabile che un'app entri e abbandoni un'attività, forse molte volte, durante dell'intera durata dell'app, ad esempio quando l'utente tocca il pulsante Indietro del dispositivo. o l'attività avvia un'altra attività.

Questa sezione tratta gli argomenti che devi conoscere per implementare correttamente le transizioni delle attività. Questi argomenti includono l'avvio di un'attività da un'altra attività, il salvataggio delle attività e ripristinare lo stato dell'attività.

Iniziare un'attività da un'altra

Spesso, un'attività deve iniziare un'altra attività in un determinato momento. Questa esigenza si verifica, ad esempio, quando un'app deve passare dalla schermata corrente a uno nuovo.

A seconda che la tua attività voglia o meno ricevere i risultati dalla nuova attività stai per iniziare, puoi avviare la nuova attività utilizzando startActivity() o il metodo startActivityForResult() . In entrambi i casi, passi in un oggetto Intent.

L'oggetto Intent specifica l'esatta l'attività da avviare o descrive il tipo di azione da eseguire. Il sistema seleziona l'attività appropriata per te, che può anche essere da un'altra applicazione. Un oggetto Intent può contengono anche piccole quantità di dati che possono essere utilizzate dall'attività avviata. Per ulteriori informazioni sul corso Intent, vedi Intenzioni e intenzione Filtri:

startActivity()

Se non è necessario che l'attività appena avviata restituisca un risultato, l'attività corrente può avviarla. chiamando il metodo startActivity() .

Quando si lavora all'interno di una propria applicazione, spesso è necessario semplicemente avviare un'attività nota. Ad esempio, il seguente snippet di codice mostra come avviare un'attività denominata SignInActivity.

Kotlin

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Java

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

L'applicazione potrebbe anche voler eseguire alcune azioni, ad esempio inviare un'email SMS o aggiornamento di stato, utilizzando i dati delle tue attività. In questo caso, l'applicazione potrebbe non disporre di attività proprie per eseguire tali azioni. in modo da poter invece sfruttare le attività fornite da altre applicazioni sul dispositivo, può eseguire tali azioni per tuo conto.

È qui che le intenzioni hanno davvero valore. Puoi creare un nuovo intent che descriva un'azione da eseguire e il sistema avvia l'app all'attività di un'altra applicazione. Se più attività possono gestire l'intento, dopodiché potrà selezionare quello da utilizzare. Ad esempio, se vuoi consentire all'utente di inviare un'email, puoi creare il seguente intent:

Kotlin

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

Java

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

L'extra EXTRA_EMAIL aggiunto all'intent è un array di stringhe di gli indirizzi email a cui deve essere inviata l'email. Quando un'applicazione email a questo intent, legge l'array di stringhe fornito inserisce gli indirizzi nella campo del modulo di composizione dell'email. In questo inizia l'attività dell'applicazione email e, quando l'utente ha finito, l'attività riprende.

startActivityForResult()

A volte potresti voler ottenere un risultato da un'attività quando termina. Ad esempio, potresti iniziare un'attività che consente all'utente di scegliere una persona da un elenco di contatti. Al termine, restituisce persona selezionata. A questo scopo, devi chiamare il startActivityForResult(Intent, int) in cui il parametro numero intero identifica la chiamata.

Questo identificatore serve a distinguere tra più chiamate a startActivityForResult(Intent, int) dalla stessa attività. Non è un identificatore globale e non rischiano di entrare in conflitto con altre app o attività. Il risultato viene restituito tramite onActivityResult(int, int, Intent) .

Quando l'attività secondaria viene chiusa, può chiamare setResult(int) a e restituire i dati all'elemento principale. L'attività figlio deve fornire un codice risultato, che può essere i risultati standard RESULT_CANCELED, RESULT_OK o valori personalizzati a partire da RESULT_FIRST_USER.

Inoltre, l'attività secondaria può restituire facoltativamente un Intent contenente gli eventuali dati aggiuntivi richiesti. L'attività genitore utilizza onActivityResult(int, int, Intent) , insieme all'identificatore intero dell'attività principale originariamente fornite, per ricevere le informazioni.

Se per qualsiasi motivo l'attività di tuo figlio non va a buon fine, ad esempio un arresto anomalo, il genitore l'attività riceve un risultato con il codice RESULT_CANCELED.

Kotlin

class MyActivity : Activity() {
    // ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            // When the user center presses, let them pick a contact.
            startActivityForResult(
                    Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
                    PICK_CONTACT_REQUEST)
            return true
        }
        return false
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        when (requestCode) {
            PICK_CONTACT_REQUEST ->
                if (resultCode == RESULT_OK) {
                    // A contact was picked. Display it to the user.
                    startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
                }
        }
    }

    companion object {
        internal val PICK_CONTACT_REQUEST = 0
    }
}

Java

public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked. Display it to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

Coordinare le attività

Quando un'attività inizia un'altra, entrambe attraversano il ciclo di vita. La prima attività smette di funzionare e passa allo stato In pausa o Interrotta, mentre l'altra viene creata l'attività. Nel caso in cui queste attività condividano dati salvati su disco o altrove, è importante comprendere che la prima attività non si interrompe completamente prima della seconda viene creato. Piuttosto, il processo per avviare il secondo si sovrappone con il processo di interrompendo la prima.

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

  1. Viene eseguito il metodo onPause() dell'attività A.
  2. onCreate() dell'attività B, onStart() e I metodi onResume() vengono eseguiti in sequenza. Ora l'attività B è incentrata sugli utenti.
  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 informazioni da un'attività all'altra.