Tasks e stack posteriore

Un'attività è un insieme di attività con cui gli utenti interagiscono quando cercano di eseguire qualcosa nella tua app. Queste attività sono organizzate in uno stack chiamato stack back nell'ordine in cui viene aperta ogni attività.

Ad esempio, un'app email potrebbe avere un'attività per mostrare un elenco di nuovi messaggi. Quando l'utente seleziona un messaggio, si apre una nuova attività per visualizzarlo. Questa nuova attività viene aggiunta allo stack precedente. Quando l'utente tocca o fa un gesto Indietro, la nuova attività termina e viene separata dall'elenco filtri.

Ciclo di vita di un'attività e il suo back stack

La schermata Home del dispositivo è il punto di partenza per la maggior parte delle attività. Quando un utente tocca l'icona di un'app o di una scorciatoia in Avvio applicazioni o nella schermata Home, l'attività dell'app viene mostrata in primo piano. Se non esistono attività per l'app, viene creata una nuova attività e l'attività principale dell'app si apre come attività principale nello stack.

Quando l'attività corrente ne avvia un'altra, la nuova attività viene inviata in cima alla pila e viene evidenziata. L'attività precedente rimane nell'elenco, ma viene arrestata. Quando un'attività viene interrotta, il sistema conserva lo stato corrente dell'interfaccia utente. Quando l'utente esegue l'azione back, l'attività corrente viene estratta dalla parte superiore dello stack ed eliminata. L'attività precedente riprende e lo stato precedente dell'interfaccia utente viene ripristinato.

Le attività nello stack non vengono mai riorganizzate, vengono spinte e separate dallo stack quando vengono avviate dall'attività corrente e eliminate dall'utente tramite il pulsante Indietro o il gesto. Di conseguenza, lo stack posteriore funziona come struttura di oggetti ultima entrata e uscita. La Figura 1 mostra una sequenza temporale in cui le attività vengono spinte e estratte da uno stack precedente.

Figura 1. Una rappresentazione di come ogni nuova attività in un'attività aggiunge un elemento allo stack precedente. Quando l'utente tocca o tocca Indietro, l'attività corrente viene eliminata e quella precedente riprende.

Mentre l'utente continua a toccare o a eseguire il gesto Indietro, ogni attività nella pila viene separata per visualizzare quella precedente, finché l'utente non torna alla schermata Home o a qualsiasi attività in esecuzione al momento dell'inizio dell'attività. Quando tutte le attività vengono rimosse dall'elenco, l'attività non esiste più.

Comportamento del tocco indietro per le attività dell'Avvio app root

Le attività dell'Avvio app radice sono attività che dichiarano un filtro intent sia con ACTION_MAIN che con CATEGORY_LAUNCHER. Queste attività sono uniche perché fungono da punti di ingresso alla tua app da Avvio applicazioni e vengono utilizzate per avviare un'attività.

Quando un utente tocca o esegue un gesto Indietro da un'attività di avvio applicazioni principale, il sistema gestisce l'evento in modo diverso a seconda della versione di Android installata sul dispositivo.

Comportamento del sistema su Android 11 e versioni precedenti
Il sistema termina l'attività.
Comportamento del sistema su Android 12 e versioni successive

Il sistema sposta l'attività e la relativa attività in background invece di completarla. Questo comportamento corrisponde al comportamento predefinito del sistema quando esci da un'app utilizzando il pulsante Home o il gesto.

Nella maggior parte dei casi, questo comportamento significa che gli utenti possono ripristinare più rapidamente l'app da uno stato caldo, anziché dover riavviare completamente l'app da uno stato a freddo.

Se devi fornire una navigazione a ritroso personalizzata, ti consigliamo di utilizzare le API AndroidX Activity anziché eseguire l'override di onBackPressed(). Le API AndroidX Activity si riferiscono automaticamente al comportamento di sistema appropriato se non ci sono componenti che intercettano il sistema. Back Tap.

Tuttavia, se la tua app esegue l'override di onBackPressed() per gestire la navigazione a ritroso e completare l'attività, aggiorna l'implementazione in modo da effettuare chiamate a super.onBackPressed() anziché terminare. La chiamata a super.onBackPressed() sposta l'attività e la relativa attività in background quando opportuno e offre un'esperienza di navigazione più coerente per gli utenti nelle app.

Attività in background e in primo piano

Figura 2. Due attività: l'attività B riceve le interazioni dell'utente in primo piano, mentre l'attività A è in background, in attesa di essere ripresa.

Un'attività è un'unità coesa che può essere spostata in sfondo quando un utente inizia una nuova attività o passa alla schermata Home. In background, tutte le attività vengono interrotte, ma lo stack precedente rimane invariato: l'attività perde lo stato attivo mentre è in corso un'altra attività, come mostrato nella Figura 2. Un'attività può quindi tornare in primo piano in modo che gli utenti possano riprendere da dove avevano interrotto.

Considera il seguente flusso per l'attività A attuale con tre attività nello stack, di cui due nell'attività corrente:

  1. L'utente utilizza il pulsante Home o il gesto, quindi avvia una nuova app da Avvio app.

    Quando appare la schermata Home, l'attività A passa in background. Quando viene avviata la nuova app, il sistema avvia un'attività per quell'app (attività B) con il proprio stack di attività.

  2. Dopo aver interagito con l'app, l'utente torna alla home page e seleziona l'app che ha avviato inizialmente l'attività A.

    Ora l'attività A è in primo piano: tutte e tre le attività nello stack sono intatte e l'attività in cima allo stack riprende. A questo punto, l'utente può anche tornare all'attività B andando alla schermata Home e selezionando l'icona dell'app che ha avviato l'attività o selezionando l'attività dell'app dalla schermata Recenti.

Istanze di attività multiple

Figura 3. È possibile creare un'istanza di una singola attività più volte.

Poiché le attività nel back stack non vengono mai riorganizzate, se l'app consente agli utenti di avviare una determinata attività da più di un'attività, viene creata una nuova istanza di quell'attività che viene creata e inviata nello stack, anziché portare all'inizio l'istanza precedente dell'attività. Di conseguenza, un'attività nell'app potrebbe essere creata più volte, anche da attività diverse, come mostrato nella figura 3.

Se l'utente torna indietro utilizzando il pulsante Indietro o il gesto, le istanze dell'attività vengono mostrate nell'ordine di apertura, ciascuna con il proprio stato di UI. Tuttavia, puoi modificare questo comportamento se non vuoi creare un'istanza di un'attività più di una volta. Per ulteriori informazioni, consulta la sezione relativa alla gestione delle attività.

Ambienti multi-finestra

Quando le app vengono eseguite contemporaneamente in un ambiente con più finestre, supportato in Android 7.0 (livello API 24) e versioni successive, il sistema gestisce le attività separatamente per ogni finestra. Ogni finestra può avere più attività. Lo stesso vale per le app Android in esecuzione sui Chromebook: il sistema gestisce attività o gruppi di attività per ogni finestra.

Riepilogo del ciclo di vita

Per riepilogare il comportamento predefinito per le attività e le attività:

  • Quando l'attività A avvia l'attività B, l'attività A viene interrotta, ma il sistema conserva il suo stato, ad esempio la posizione di scorrimento e l'eventuale testo inserito nei moduli. Se l'utente tocca o utilizza il gesto Indietro nell'Attività B, l'attività A riprende con lo stato ripristinato.

  • Quando l'utente abbandona un'attività utilizzando il pulsante Home o il gesto, l'attività corrente viene interrotta e la relativa attività viene spostata in background. Il sistema conserva lo stato di ogni attività nell'attività. Se l'utente in seguito riprende l'attività selezionando l'icona in Avvio applicazioni che l'ha avviata, l'attività viene visualizzata in primo piano e la riprende in cima all'elenco.

  • Se l'utente tocca o fa un gesto Indietro, l'attività corrente viene estratta dalla pila ed eliminata. L'attività precedente nello stack riprende. Quando un'attività viene eliminata, il sistema non conserva lo stato dell'attività.

    Questo comportamento è diverso per le attività dell'Avvio app root quando la tua app è in esecuzione su un dispositivo con Android 12 o versioni successive.

  • Puoi creare istanze di attività più volte, anche da altre attività.

Gestisci le attività

Android gestisce le attività e il back stack posizionando tutte le attività iniziate in successione nella stessa attività, in uno stack ultime in ordine di importanza e prima fuori. Questo funziona benissimo per la maggior parte delle app e di solito non devi preoccuparti di come le tue attività sono associate alle attività o di come sono presenti nello stack posteriore.

Tuttavia, potresti decidere di interrompere il comportamento normale. Ad esempio, potresti volere che un'attività nella tua app inizi una nuova attività all'avvio, anziché essere inserita nell'attività corrente. Oppure, quando avvii un'attività, potresti voler portare avanti un'istanza esistente dell'attività, anziché creare una nuova istanza in aggiunta allo stack precedente. Oppure potresti voler cancellare lo stack posteriore da tutte le attività ad eccezione dell'attività principale quando l'utente abbandona l'attività.

Puoi fare queste e altre operazioni utilizzando gli attributi nell'elemento manifest di <activity> e i flag nell'intent che passi a startActivity().

Questi sono gli attributi <activity> principali che puoi utilizzare per gestire le attività:

Questi sono i principali flag di intent che puoi utilizzare:

Le seguenti sezioni descrivono come utilizzare questi attributi del file manifest e questi flag di intent per definire il modo in cui le attività vengono associate alle attività e il loro comportamento nel back stack.

Sono state inoltre illustrate le considerazioni su come attività e attività sono rappresentate e gestite nella schermata Recenti. Normalmente, consenti al sistema di definire il modo in cui l'attività e le attività sono rappresentate nella schermata Recenti e non è necessario modificare questo comportamento. Per ulteriori informazioni, consulta la schermata Recenti.

Definisci le modalità di avvio

Le modalità di avvio consentono di definire in che modo una nuova istanza di un'attività viene associata all'attività corrente. Puoi definire le modalità di avvio in due modi, descritti nelle sezioni che seguono:

Pertanto, se l'attività A avvia l'attività B, l'attività B può definire nel manifest la modalità di associazione all'attività corrente, mentre l'attività A può utilizzare un flag di intent per richiedere l'associazione dell'attività B all'attività corrente.

Se entrambe le attività definiscono il modo in cui l'attività B viene associata a un'attività, la richiesta dell'attività A, come definita nell'intent, viene rispettata rispetto alla richiesta dell'attività B, come definita nel manifest.

Definisci le modalità di avvio utilizzando il file manifest

Quando dichiari un'attività nel file manifest, puoi specificare in che modo l'attività viene associata a un'attività utilizzando l'attributo launchMode dell'elemento <activity>.

Esistono cinque modalità di lancio che puoi assegnare all'attributo launchMode:

  1. "standard"
    La modalità predefinita. Il sistema crea una nuova istanza dell'attività nell'attività da cui è stata avviata e instrada l'intent a questa attività. L'attività può essere instaurata più volte, ogni istanza può appartenere ad attività diverse e un'attività può avere più istanze.
  2. "singleTop"
    Se esiste già un'istanza dell'attività nella parte superiore dell'attività corrente, il sistema inoltra l'intent a quell'istanza tramite una chiamata al metodo onNewIntent(), anziché creare una nuova istanza dell'attività. L'attività viene instaurata più volte, ogni istanza può appartenere ad attività diverse e un'attività può avere più istanze (ma solo se l'attività in cima dallo stack non è un'istanza esistente dell'attività).

    Ad esempio, supponi che lo stack precedente di un'attività sia costituito dall'attività principale A con le attività B, C e D in cima (quindi lo stack è A-B-C-D, con la D in alto). Un intent arriva per un'attività di tipo D. Se D ha la modalità di avvio predefinita di "standard", viene avviata una nuova istanza della classe e lo stack diventa A-B-C-D-D. Tuttavia, se la modalità di avvio di D è "singleTop", l'istanza esistente di D riceve l'intent tramite onNewIntent(), perché si trova in cima allo stack, mentre lo stack rimane A-B-C-D. Se, invece, arriva un intent per un'attività di tipo B, viene aggiunta una nuova istanza di B allo stack anche se la sua modalità di avvio è "singleTop".

  3. "singleTask"
    Il sistema crea l'attività alla radice di una nuova attività o ne individua l'attività in un'attività esistente con la stessa affinità. Se esiste già un'istanza dell'attività, il sistema instrada l'intent all'istanza esistente tramite una chiamata al suo metodo onNewIntent(), anziché creare una nuova istanza. Nel frattempo, tutte le altre attività successive vengono distrutte.
  4. "singleInstance".
    Il comportamento è lo stesso di "singleTask", ad eccezione del fatto che il sistema non avvia altre attività nell'attività che contiene l'istanza. L'attività è sempre l'unico e l'unico membro della sua attività. Tutte le attività avviate da questa si aprono in un'attività separata.
  5. "singleInstancePerTask".
    L'attività può essere eseguita solo come attività principale dell'attività, ovvero la prima attività che l'ha creata, perciò può esserci una sola istanza di questa attività in un'attività. A differenza della modalità di avvio singleTask, questa attività può essere avviata in più istanze e attività diverse se è impostato il flag FLAG_ACTIVITY_MULTIPLE_TASK o FLAG_ACTIVITY_NEW_DOCUMENT.

Come ulteriore esempio, l'app browser Android dichiara che l'attività del browser web si apre sempre nella propria attività specificando la modalità di avvio singleTask nell'elemento <activity>. Ciò significa che se la tua app tenta di aprire il browser Android, la sua attività non viene inserita nella stessa attività dell'app. Viene invece avviata una nuova attività per il browser o, se il browser ha già un'attività in esecuzione in background, l'attività viene anticipata per gestire il nuovo intent.

Indipendentemente dal fatto che un'attività venga avviata in una nuova attività o nella stessa attività dell'attività che l'ha avviata, il pulsante Indietro e il gesto portano sempre l'utente all'attività precedente. Tuttavia, se avvii un'attività che specifica la modalità di avvio di singleTask e esiste un'istanza di tale attività in un'attività in background, l'intera attività viene portata in primo piano. A questo punto, lo stack precedente include tutte le attività dell'attività portate avanti in cima allo stack. La figura 4 mostra questo tipo di scenario.

Figura 4. Una rappresentazione di come un'attività con modalità di avvio "singleTask" viene aggiunta allo stack posteriore. Se l'attività fa già parte di un'attività in background con il proprio stack posteriore, viene fatto avanti anche l'intero stack posteriore, in aggiunta all'attività corrente.

Per ulteriori informazioni sull'utilizzo delle modalità di avvio nel file manifest, consulta la documentazione relativa agli elementi <activity>.

Definisci le modalità di avvio utilizzando i flag di intent

Quando avvii un'attività, puoi modificare l'associazione predefinita di un'attività alla relativa attività includendo flag nell'intent che pubblichi a startActivity(). I flag che puoi utilizzare per modificare il comportamento predefinito sono i seguenti:

FLAG_ACTIVITY_NEW_TASK

Il sistema avvia l'attività in una nuova attività. Se un'attività è già in esecuzione per l'attività avviata, viene messa in primo piano con l'ultimo stato ripristinato e l'attività riceve il nuovo intent in onNewIntent().

Questo produce lo stesso comportamento del valore "singleTask" launchMode discusso nella sezione precedente.

FLAG_ACTIVITY_SINGLE_TOP

Se l'attività avviata è l'attività corrente, nella parte superiore dello stack posteriore, l'istanza esistente riceve una chiamata a onNewIntent() anziché creare una nuova istanza dell'attività.

Questo produce lo stesso comportamento del valore "singleTop" launchMode discusso nella sezione precedente.

FLAG_ACTIVITY_CLEAR_TOP

Se l'attività avviata è già in esecuzione nell'attività corrente, invece di avviare una nuova istanza di quell'attività, il sistema elimina tutte le altre attività nell'attività corrente. L'intent viene trasmesso all'istanza ripresa dell'attività, ora in alto, tramite onNewIntent().

Non esiste alcun valore per l'attributo launchMode che produce questo comportamento.

FLAG_ACTIVITY_CLEAR_TOP viene utilizzato più spesso insieme a FLAG_ACTIVITY_NEW_TASK. Se utilizzati insieme, questi flag individuano un'attività esistente in un'altra attività e la collocano in una posizione in cui può rispondere all'intent.

Gestire le affinità

Un'affinità indica a quale attività "preferisce" appartenere. Per impostazione predefinita, tutte le attività della stessa app hanno un'affinità tra loro e "preferiscono" essere nella stessa attività.

Tuttavia, puoi modificare l'affinità predefinita per un'attività. Le attività definite in app diverse possono condividere un'affinità, mentre alle attività definite nella stessa app possono essere assegnate affinità diverse.

Puoi modificare l'affinità di un'attività utilizzando l'attributo taskAffinity dell'elemento <activity>.

L'attributo taskAffinity accetta un valore stringa che deve essere diverso dal nome del pacchetto predefinito dichiarato nell'elemento <manifest>, perché il sistema utilizza questo nome per identificare l'affinità dell'attività predefinita per l'app.

L'affinità entra in gioco in due circostanze:

  1. Quando l'intent che lancia un'attività contiene il flag FLAG_ACTIVITY_NEW_TASK.

    Per impostazione predefinita, viene avviata una nuova attività nell'attività dell'attività che ha chiamato startActivity(). Viene inviato allo stesso stack secondario del chiamante.

    Tuttavia, se l'intent passato a startActivity() contiene il flag FLAG_ACTIVITY_NEW_TASK, il sistema cerca un'altra attività per ospitare la nuova attività. Spesso si tratta di un compito nuovo. Ma non deve esserlo. Se è già presente un'attività con la stessa affinità della nuova attività, l'attività viene avviata in quell'attività. In caso contrario, viene avviata una nuova attività.

    Se questo flag causa l'inizio di una nuova attività da parte di un'attività e l'utente utilizza il pulsante Home o il gesto per uscire dall'attività, l'utente deve poter poter tornare all'attività in qualche modo. Alcune entità, come il gestore delle notifiche, avviano sempre le attività in un'attività esterna, mai come parte delle proprie, quindi inseriscono sempre FLAG_ACTIVITY_NEW_TASK negli intent che passano a startActivity().

    Se un'entità esterna che potrebbe utilizzare questo flag può richiamare la tua attività, assicurati che l'utente abbia un modo indipendente per tornare all'attività avviata, ad esempio con un'icona in Avvio applicazioni, in cui l'attività principale dell'attività ha un filtro di intent CATEGORY_LAUNCHER. Per ulteriori informazioni, consulta la sezione relativa all'avvio delle attività.

  2. Quando l'attributo allowTaskReparenting di un'attività è impostato su "true".

    In questo caso, l'attività può essere spostata dall'attività in cui inizia a quella per cui ha un'affinità quando diventa in primo piano.

    Ad esempio, supponi che un'attività che registra le condizioni meteo in determinate città sia definita come parte di un'app di viaggi. Ha la stessa affinità delle altre attività nella stessa app (l'affinità predefinita dell'app) e può essere associata nuovamente all'attributo con questo attributo.

    Quando una delle tue attività avvia l'attività reporter meteo, inizialmente appartiene alla stessa attività della tua attività. Tuttavia, quando l'attività dell'app di viaggi viene visualizzata in primo piano, l'attività del reporter meteo viene riassegnata e visualizzata al suo interno.

Cancella lo stack posteriore

Se l'utente abbandona un'attività per molto tempo, il sistema cancella tutte le attività, tranne l'attività principale. Quando l'utente torna all'attività, viene ripristinata solo l'attività principale. Il sistema si comporta in questo modo in base al presupposto che, dopo un periodo di tempo prolungato, gli utenti abbiano abbandonato ciò che stavano facendo prima e tornino all'attività per iniziare qualcosa di nuovo.

Per modificare questo comportamento puoi utilizzare alcuni attributi di attività:

alwaysRetainTaskState
Quando questo attributo è impostato su "true" nell'attività principale di un'attività, il comportamento predefinito appena descritto non si verifica. L'attività conserva tutte le attività nel proprio stack anche dopo un lungo periodo.
clearTaskOnLaunch

Se questo attributo è impostato su "true" nell'attività principale di un'attività, quest'ultima viene cancellata dall'attività principale ogni volta che l'utente abbandona l'attività e vi torna. In altre parole, è il contrario di alwaysRetainTaskState. L'utente torna sempre all'attività nello stato iniziale, anche dopo averla lasciata per un solo momento.

finishOnTaskLaunch

Questo attributo è simile a clearTaskOnLaunch, ma opera su una singola attività, non su un'intera attività. Inoltre, può causare il completamento di qualsiasi attività tranne quella principale. Se è impostato su "true", l'attività rimane parte dell'attività solo per la sessione corrente. Se l'utente abbandona l'attività e poi torna all'attività, questa non è più presente.

Avvia un'attività

Puoi configurare un'attività come punto di ingresso per un'attività assegnandole un filtro per intent con "android.intent.action.MAIN" come azione specificata e "android.intent.category.LAUNCHER" come categoria specificata:

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

Un filtro per intent di questo tipo fa sì che vengano visualizzate un'icona e un'etichetta dell'attività in Avvio applicazioni, offrendo agli utenti un modo per avviare l'attività e tornare all'attività creata in qualsiasi momento dopo l'avvio.

Questa seconda funzionalità è importante. Gli utenti devono essere in grado di uscire da un'attività e tornarvi in un secondo momento utilizzando l'Avvio attività. Per questo motivo, utilizza solo le due modalità di avvio che contrassegnano le attività come sempre che avviano un'attività, "singleTask" e "singleInstance", quando l'attività ha un filtro ACTION_MAIN e CATEGORY_LAUNCHER.

Immagina, ad esempio, cosa potrebbe accadere se il filtro non fosse presente: un intent avvia un'attività "singleTask", avvia una nuova attività e l'utente dedica del tempo a quell'attività. L'utente usa quindi il pulsante Home o il gesto. L'attività viene inviata in background e non è visibile. Ora l'utente non ha modo di tornare all'attività, perché non è rappresentata in Avvio applicazioni.

Per quei casi in cui non vuoi che l'utente possa tornare a un'attività, imposta l'elemento <activity> finishOnTaskLaunch su "true". Per ulteriori informazioni, consulta la sezione relativa allo svuotamento dello stack posteriore.

Ulteriori informazioni su come le attività e le attività sono rappresentate e gestite nella schermata Recenti sono disponibili nella schermata Recenti.

Altre risorse