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,
NavControllersposta 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()eNavController.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:
- Navigazione circolare: scopri come evitare un backstack troppo pieno nei casi in cui i flussi di navigazione sono circolari.
- Destinazioni della finestra di dialogo: scopri come le destinazioni della finestra di dialogo introducono considerazioni uniche su come gestire il back stack.