Nawigacja i stos tylny

NavController zawiera „stos wsteczny”, który zawiera miejsca docelowe odwiedzonych przez użytkownika. Gdy użytkownik przechodzi między ekranami w aplikacji, NavController dodaje miejsca docelowe do stosu wstecznego oraz je z niego usuwa.

W stosunku do stosu wstecznego struktura danych typu „ostatnie wejście, pierwsze wyjście”. W ten sposób NavController przenosi elementy do i wyskakuje z góry stosu.

Podstawowe działanie

Oto najważniejsze fakty dotyczące działania stosu wstecznego, które musisz wziąć pod uwagę:

  • Pierwsze miejsce docelowe: gdy użytkownik otwiera aplikację, NavController przenosi pierwsze miejsce docelowe na górę stosu wstecznego.
  • Przekazywanie na stos: każde wywołanie NavController.navigate() przesuwa dane miejsce docelowe na szczyt stosu.
  • Miejsce docelowe u góry strony: kliknięcie W górę lub Wstecz wywołuje odpowiednio metody NavController.navigateUp() i NavController.popBackStack(). Usuwają z grupy pierwsze miejsce docelowe. Na stronie Zasady nawigacji znajdziesz więcej informacji o różnicy między przyciskami góra i wstecz.

Odpręż się

Metoda NavController.popBackStack() próbuje usunąć bieżące miejsce docelowe z stosu wstecznego i przejść do poprzedniego miejsca docelowego. Spowoduje to cofnięcie użytkownika o jeden krok w historii nawigacji. Zwraca wartość logiczną wskazującą, czy wiadomość powróciła do miejsca docelowego.

Wróć do konkretnego miejsca docelowego

Możesz też użyć aplikacji popBackStack(), by przejść do konkretnego miejsca docelowego. Aby to zrobić, wykorzystaj jedno z jego przeciążeń. Jest kilka funkcji, które umożliwiają przekazywanie identyfikatora, np. liczba całkowita id lub ciąg znaków route. Przeciążenia te kierują użytkownika do miejsca docelowego powiązanego z danym identyfikatorem. Co ważne, umieszcza wszystko w stosie nad tym miejscem docelowym.

Te przeciążenia również przyjmują wartość logiczną inclusive. Określa, czy po przejściu do określonego miejsca docelowego NavController powinno też usunąć określone miejsce docelowe ze stosu.

Weźmy na przykład ten krótki fragment kodu:

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

NavController wraca do miejsca docelowego z identyfikatorem liczby całkowitej destinationId. Wartość argumentu inclusive to true, więc NavController pobiera też dane miejsce docelowe ze stosu wstecznego.

Obsługa nieudanego okienka wyskakującego

Gdy popBackStack() zwraca wartość false, kolejne wywołanie metody NavController.getCurrentDestination() zwraca wartość null. Oznacza to, że aplikacja usunęła ostatnie miejsce docelowe ze stosu. W takim przypadku użytkownik widzi tylko pusty ekran.

Może się tak zdarzyć w tych przypadkach:

  • popBackStack() nie wyskoczył(a) ze stosu.
  • popBackStack() usunął miejsce docelowe ze stosu wstecznego i stos jest teraz pusty.

Aby rozwiązać ten problem, musisz przejść do nowego miejsca docelowego lub wywołać funkcję finish() w aktywności, aby ją zakończyć. Można to zademonstrować za pomocą tego fragmentu kodu:

Kotlin

...

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

kawa

...

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

Zbliż się do miejsca docelowego

Aby usunąć miejsca docelowe ze stosu wstecznego podczas przechodzenia z jednego miejsca docelowego do innego, dodaj argument popUpTo() do powiązanego wywołania funkcji navigate(). popUpTo() nakazuje bibliotece Nawigacji usunięcie niektórych miejsc docelowych ze stosu wstecznego w ramach wywołania navigate(). Wartość parametru to identyfikator miejsca docelowego na stosie wstecznym. Identyfikator może być liczbą całkowitą id lub ciągiem route.

Możesz dołączyć argument dla parametru inclusive o wartości true, aby wskazać, że miejsce docelowe podane w zasadzie popUpTo() też powinno zostać usunięte ze stosu.

Aby wdrożyć tę funkcję automatycznie, przekaż popUpTo() do navigate() w ramach NavOptions z inclusive ustawionym na true. Działa to zarówno w tworzeniu, jak i w widokach danych.

Zapisz stan po wyświetleniu reklamy

Gdy do nawigacji do miejsca docelowego używasz polecenia popUpTo, możesz opcjonalnie zapisać stany wszystkich miejsc docelowych, które zostały usunięte ze stosu wstecznego.

Aby włączyć tę opcję, określ popUpToSaveState jako true w powiązanych action lub wywołaj NavController.navigate().

Gdy jedziesz do miejsca docelowego, możesz też określić restoreSaveState jako true, aby automatycznie przywrócić stan powiązany z tym miejscem w usłudze destination.

Przykład w formacie XML

Oto przykład kodu popUpTo w pliku XML, w którym użyto działania:

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

Przykłady tworzenia wiadomości

Poniżej znajdziesz pełny przykład podobnej funkcji w sekcji Utwórz:

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: String = "destination_a"
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable("destination_a") {
            DestinationA(
                onNavigateToB = {
                // 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") {
                            inclusive = true
                            saveState = true
                        }
                    }
                },
            )
        }
        composable("destination_b") { DestinationB(/* ... */) }
    }
}

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

Bardziej szczegółowo możesz zmienić sposób wywoływania funkcji NavController.navigate() na te sposoby:

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

Ogólne informacje o przekazywaniu opcji do NavController.navigate() znajdziesz w przewodniku po opcjach.

Przebijaj za pomocą działań

Podczas nawigacji za pomocą działania możesz opcjonalnie wydzielić dodatkowe miejsca docelowe ze stosu wstecznego. Jeśli na przykład w aplikacji następuje początkowy proces logowania, to po zalogowaniu się użytkownika należy usunąć ze stosu wstecznego wszystkie miejsca docelowe związane z logowaniem, aby przycisk Wstecz nie kierował użytkowników z powrotem do procesu logowania.

Materiały dodatkowe

Więcej informacji znajdziesz na tych stronach:

  • Nawigacja kołowa: dowiedz się, jak uniknąć nadmiernego nakładania się tyłu w przypadkach, gdy przepływy nawigacji mają charakter cykliczny.
  • Miejsca docelowe okien: dowiedz się, jak miejsca docelowe okien wprowadzają specjalne zasady zarządzania stosem wstecznym.