Navigazione e stack posteriore

NavController contiene un "back stack" che include le destinazioni visitate dall'utente. Man mano che l'utente naviga tra le schermate dell'app, NavController aggiunge e rimuove destinazioni al back stack e dal back stack.

In quanto stack, lo stack precedente è una struttura di dati "ultimo inserito, primo estratto". Pertanto, NavController inserisce gli elementi nella parte superiore della pila e li estrae dalla parte superiore della pila.

Comportamento di base

Di seguito sono riportati i fatti principali da considerare in merito al comportamento dello stack di backend:

  • Prima destinazione:quando l'utente apre l'app, NavController sposta la prima destinazione in cima al back stack.
  • Pushing to the stack:ogni chiamata NavController.navigate() spinge la destinazione specificata in cima allo stack.
  • Destinazione principale: toccando Su o Indietro vengono chiamati i metodi NavController.navigateUp() e NavController.popBackStack(), rispettivamente. Viene visualizzata la prima destinazione della pila. Per ulteriori informazioni sulla differenza tra Su e Indietro, consulta la pagina Principi di navigazione.

Pop back

Il metodo NavController.popBackStack() tenta di estrarre la destinazione corrente dallo stack precedente e di passare alla destinazione precedente. In questo modo l'utente torna indietro di un passaggio nella cronologia di navigazione. Restituisce un valore booleano che indica se è tornato correttamente alla destinazione.

Tornare a una destinazione specifica

Puoi anche utilizzare popBackStack() per raggiungere una destinazione specifica. Per farlo, utilizza uno dei suoi overload. Esistono diversi tipi che consentono di passare un identificatore, ad esempio un numero intero id o una stringa route. Questi sovraccarichi portano l'utente alla destinazione associata all'identificatore specificato. Fondamentalmente, estrae tutto dallo stack sopra la destinazione.

Questi sovraccarichi accettano anche un valore booleano inclusive. Determina se NavController deve anche rimuovere la destinazione specificata dal back stack dopo averla raggiunta.

Considera questo breve snippet come esempio:

navController.popBackStack(R.id.destinationId, true)

In questo caso, NavController torna alla destinazione con l'ID intero destinationId. Poiché il valore dell'argomento inclusive è true, anche NavController estrae la destinazione specificata dal back stack.

Gestire un pop back non riuscito

Quando popBackStack() restituisce false, una chiamata successiva a NavController.getCurrentDestination() restituisce null. Ciò significa che l'app ha rimosso l'ultima destinazione dal back stack. In questo caso, l'utente vede solo una schermata vuota.

Ciò può verificarsi nei seguenti casi:

  • popBackStack() non ha estratto nulla dalla pila.
  • popBackStack() ha estratto una destinazione dal back stack e lo stack è ora vuoto.

Per risolvere il problema, devi raggiungere una nuova destinazione o chiamare finish() sull'attività per terminarla. Il seguente snippet mostra questo aspetto:

kotlin

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

java

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish();
}

Visualizzare un popup per una destinazione

Per rimuovere le destinazioni dal back stack quando passi da una destinazione all'altra, aggiungi un argomento popUpTo() alla chiamata della funzione navigate() associata. popUpTo() indica alla libreria di navigazione di rimuovere alcune destinazioni dallo stack precedente nell'ambito della chiamata a navigate(). Il valore del parametro è l'identificatore di una destinazione nello stack precedente. L'identificatore può essere un numero intero id o una stringa route.

Puoi includere un argomento per il parametro inclusive con un valore di true per indicare che la destinazione specificata in popUpTo() deve anche essere rimossa dallo stack precedente.

Per implementare questo programma a livello di codice, passa popUpTo() a navigate() come parte di NavOptions con inclusive impostato su true. Funziona sia in Composizione che in Visualizzazioni.

Salva lo stato quando viene visualizzato un popup

Quando utilizzi popUpTo per raggiungere una destinazione, puoi facoltativamente salvare lo stack indietro e gli stati di tutte le destinazioni rimosse dallo stack indietro. Puoi quindi ripristinare il back stack e le destinazioni quando navighi verso quella destinazione in un secondo momento. In questo modo puoi conservare lo stato per una determinata destinazione e avere più back stack.

Per farlo a livello di programmazione, specifica saveState = true quando aggiungi popUpTo alle opzioni di navigazione.

Puoi anche specificare restoreState = true nelle opzioni di navigazione per ripristinare automaticamente il back stack e lo stato associato alla destinazione.

Ad esempio:

navController.navigate(
    route = route,
    navOptions =  navOptions {
        popUpTo<A>{ saveState = true }
        restoreState = true
    }
)

Per attivare il salvataggio e il ripristino dello stato in XML, definisci popUpToSaveState come true e restoreState come true rispettivamente nel action associato.

Esempio di composizione

Di seguito è riportato un esempio completo della stessa operazione in Compose:

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: Any = A
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable<A> {
            DestinationA(
                onNavigateToB = {
                // Pop everything up to, and including, the A destination off
                // the back stack, saving the back stack and the state of its
                // destinations.
                // Then restore any previous back stack state associated with
                // the B destination.
                // Finally navigate to the B destination.
                    navController.navigate(route = B) {
                        popUpTo<A> {
                            inclusive = true
                            saveState = true
                        }
                        restoreState = true
                    }
                },
            )
        }
        composable<B> { DestinationB(/* ... */) }
    }
}

@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
    Button(onClick = onNavigateToB) {
        Text("Go to A")
    }
}

In modo più granulare, puoi modificare il modo in cui chiami NavController.navigate() nei seguenti modi:

// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a")
}

// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}

Per informazioni generali sul passaggio di opzioni a NavController.navigate(), consulta la guida Navigare con le opzioni.

Esempio XML

Ecco un esempio di popUpTo in XML, utilizzando un'azione:

<action
  android:id="@+id/action_a_to_b"
  app:destination="@id/b"
  app:popUpTo="@+id/a"
  app:popUpToInclusive="true"
  app:restoreState=”true”
  app:popUpToSaveState="true"/>

Pop utilizzando le azioni

Quando navighi utilizzando un'azione, puoi estrarre facoltativamente destinazioni aggiuntive dalla cronologia. Ad esempio, se la tua app ha un flusso di accesso iniziale, una volta che un utente ha eseguito l'accesso, devi rimuovere tutte le destinazioni correlate all'accesso dallo stack precedente in modo che il pulsante Indietro non riporti gli utenti al flusso di accesso.

Letture aggiuntive

Per saperne di più, leggi le seguenti pagine: