Navigation und Back Stack

Die NavController enthält einen Backstack mit den Zielen, die der Nutzer besucht hat. Wenn der Nutzer in Ihrer App zu verschiedenen Bildschirmen navigiert, fügt NavController dem Backstack Ziele hinzu und entfernt sie daraus.

Der Backstack ist ein Stapel und damit eine „Last in, first out“-Datenstruktur. Mit NavController werden Elemente also oben auf den Stapel gelegt und von dort entfernt.

Grundlegendes Verhalten

Das sind die wichtigsten Fakten, die Sie in Bezug auf das Verhalten des Backstacks berücksichtigen sollten:

  • Erstes Ziel:Wenn der Nutzer die App öffnet, wird das erste Ziel durch NavController oben auf den Backstack verschoben.
  • Auf den Stapel legen:Bei jedem Aufruf NavController.navigate() wird das angegebene Ziel oben auf den Stapel gelegt.
  • Pop-up-Ziel: Wenn Sie auf Nach oben oder Zurück tippen, werden die Methoden NavController.navigateUp() bzw. NavController.popBackStack() aufgerufen. Sie entfernen das oberste Ziel aus dem Stapel. Weitere Informationen zum Unterschied zwischen Aufwärts und Zurück finden Sie auf der Seite Navigationsgrundsätze.

Zurück

Mit der Methode NavController.popBackStack() wird versucht, das aktuelle Ziel aus dem Back Stack zu entfernen und zum vorherigen Ziel zu navigieren. Dadurch wird der Nutzer effektiv einen Schritt in seinem Navigationsverlauf zurückgesetzt. Es wird ein boolescher Wert zurückgegeben, der angibt, ob das Zurückkehren zum Ziel erfolgreich war.

Zurück zu einem bestimmten Ziel wechseln

Sie können auch popBackStack() verwenden, um zu einem bestimmten Ziel zu navigieren. Verwenden Sie dazu eine der Überladungen. Es gibt mehrere, mit denen Sie eine Kennung übergeben können, z. B. eine Ganzzahl id oder einen String route. Diese Überladungen leiten den Nutzer zum Ziel weiter, das mit der angegebenen Kennung verknüpft ist. Wichtig ist, dass sie alles auf dem Stapel über diesem Ziel entfernen.

Diese Überladungen akzeptieren auch einen inclusive-Booleschen Wert. Sie bestimmt, ob NavController das angegebene Ziel auch aus dem Backstack entfernen soll, nachdem es aufgerufen wurde.

Hier ein kurzes Beispiel:

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

Hier wird NavController mit der Ganzzahl-ID destinationId wieder auf dem Ziel-Stack platziert. Da der Wert des inclusive-Arguments true ist, wird das angegebene Ziel auch durch NavController aus dem Backstack entfernt.

Fehlgeschlagenen Pop-Back-Vorgang verarbeiten

Wenn popBackStack() den Wert false zurückgibt, gibt ein nachfolgender Aufruf von NavController.getCurrentDestination() den Wert null zurück. Das bedeutet, dass die App das letzte Ziel aus dem Backstack entfernt hat. In diesem Fall sieht der Nutzer nur einen leeren Bildschirm.

Das kann in den folgenden Fällen passieren:

  • popBackStack() hat nichts aus dem Stapel entfernt.
  • popBackStack() hat ein Ziel aus dem Backstack entfernt und der Stack ist jetzt leer.

Um das Problem zu beheben, müssen Sie zu einem neuen Ziel navigieren oder finish() aufrufen, um die Aktivität zu beenden. Das folgende Snippet veranschaulicht dies:

kotlin

...

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

Java

...

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

Pop-up-Fenster für ein Ziel

Wenn Sie Ziele aus dem Backstack entfernen möchten, wenn Sie von einem Ziel zu einem anderen navigieren, fügen Sie dem zugehörigen navigate()-Funktionsaufruf ein popUpTo()-Argument hinzu. popUpTo() weist die Navigationsbibliothek an, einige Ziele aus dem Backstack zu entfernen, wenn navigate() aufgerufen wird. Der Parameterwert ist die Kennzeichnung eines Ziels im Backstack. Die Kennung kann eine Ganzzahl id oder ein String route sein.

Sie können ein Argument für den Parameter inclusive mit dem Wert true einfügen, um anzugeben, dass das in popUpTo() angegebene Ziel auch aus dem Backstack entfernt werden soll.

Um dies programmatisch zu implementieren, übergeben Sie popUpTo() an navigate() als Teil von NavOptions mit inclusive auf true festgelegt. Das funktioniert sowohl in Compose als auch in Views.

Status beim Einblenden speichern

Wenn Sie popUpTo verwenden, um zu einem Ziel zu navigieren, können Sie optional den Backstack und die Status aller Ziele speichern, die aus dem Backstack entfernt wurden. Sie können den Backstack und die Ziele dann wiederherstellen, wenn Sie später zu diesem Ziel navigieren. So können Sie den Status für ein bestimmtes Ziel beibehalten und mehrere Backstacks haben.

Wenn Sie dies programmatisch tun möchten, geben Sie saveState = true an, wenn Sie popUpTo zu Ihren Navigationsoptionen hinzufügen.

Sie können auch restoreState = true in Ihren Navigationsoptionen angeben, um den Backstack und den mit dem Ziel verknüpften Status automatisch wiederherzustellen.

Beispiel:

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

Wenn Sie den Status in XML speichern und wiederherstellen möchten, definieren Sie popUpToSaveState als true und restoreState als true in der zugehörigen action.

Beispiel für XML

Hier ist ein Beispiel für popUpTo in XML mit einer Aktion:

<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"/>

Beispiel für das Verfassen

Hier ein vollständiges Beispiel für dasselbe 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")
    }
}

Sie haben folgende Möglichkeiten, den Aufruf von NavController.navigate() zu ändern:

// 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
}

Allgemeine Informationen zum Übergeben von Optionen an NavController.navigate() finden Sie im Leitfaden „Mit Optionen navigieren“.

Pop mit Aktionen

Wenn Sie mit einer Aktion navigieren, können Sie optional zusätzliche Ziele aus dem Backstack entfernen. Wenn Ihre App beispielsweise einen anfänglichen Anmeldevorgang hat, sollten Sie nach der Anmeldung eines Nutzers alle anmeldebezogenen Ziele aus dem Back Stack entfernen, damit Nutzer nicht über den Button „Zurück“ wieder zum Anmeldevorgang zurückkehren.

Weitere Informationen

Weitere Informationen finden Sie auf den folgenden Seiten:

  • Kreisförmige Navigation: Hier erfahren Sie, wie Sie einen überfüllten Backstack bei kreisförmigen Navigationsabläufen vermeiden können.
  • Dialogziele: Hier erfahren Sie, wie sich Dialogziele auf die Verwaltung des Backstacks auswirken.