Obiekt NavController zawiera „stos wsteczny” z miejscami docelowymi, które odwiedził użytkownik. Gdy użytkownik przechodzi do kolejnych ekranów w aplikacji, komponent NavController dodaje i usuwa miejsca docelowe ze stosu wstecznego.
Stos to struktura danych typu „ostatni na wejściu, pierwszy na wyjściu”. Element NavController umieszcza elementy na wierzchołku stosu i zdejmuje je z niego.
Podstawowe działanie
Oto najważniejsze fakty dotyczące działania stosu:
- Pierwsze miejsce docelowe: gdy użytkownik otworzy aplikację,
NavControllerprzesunie pierwsze miejsce docelowe na górę stosu wstecznego. - Dodawanie do stosu: każde wywołanie
NavController.navigate()dodaje podane miejsce docelowe na górę stosu. - Wyskakujące miejsce docelowe: kliknięcie W górę lub Wstecz powoduje wywołanie odpowiednio metod
NavController.navigateUp()iNavController.popBackStack(). Usuwa z góry stosu miejsce docelowe. Więcej informacji o różnicach między przyciskami Wstecz i W górę znajdziesz na stronie Zasady nawigacji.
Wróć
Metoda NavController.popBackStack() próbuje usunąć bieżące miejsce docelowe z listy wstecznej i przejść do poprzedniego miejsca docelowego. Spowoduje to cofnięcie użytkownika o 1 krok w historii nawigacji. Zwraca wartość logiczną wskazującą, czy udało się wrócić do miejsca docelowego.
Powrót do określonego miejsca docelowego
Możesz też użyć popBackStack(), aby przejść do konkretnego miejsca docelowego. Aby to zrobić, użyj jednego z przeciążeń. Istnieje kilka sposobów przekazywania identyfikatora, np. liczby całkowitej id lub ciągu znaków route. Te przeciążenia przenoszą użytkownika do miejsca docelowego powiązanego z podanym identyfikatorem. Co ważne, usuwają one wszystko ze stosu powyżej tego miejsca docelowego.
Te przeciążenia przyjmują też wartość logiczną inclusive. Określa, czy po przejściu do określonego miejsca docelowego element NavController powinien również usunąć to miejsce ze stosu wstecznego.
Oto przykład krótkiego fragmentu kodu:
navController.popBackStack(R.id.destinationId, true)
W tym przypadku NavController wraca do miejsca docelowego z identyfikatorem liczbowym
destinationId. Ponieważ wartość argumentu inclusive to true, funkcja NavController usuwa też podane miejsce docelowe z listy wstecznej.
Obsługa nieudanego powrotu
Gdy funkcja popBackStack() zwróci wartość false, kolejne wywołanie funkcji NavController.getCurrentDestination() zwróci wartość null. Oznacza to, że aplikacja usunęła ostatnie miejsce docelowe ze stosu wstecznego. W takim przypadku użytkownik widzi tylko pusty ekran.
Może się tak zdarzyć w tych przypadkach:
popBackStack()nie usunął niczego ze stosu.popBackStack()usunął miejsce docelowe z listy wstecznej i lista jest teraz pusta.
Aby rozwiązać ten problem, musisz przejść do nowego miejsca docelowego lub zadzwonić finish(), aby zakończyć aktywność. Ilustruje to ten fragment kodu:
kotlin
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish()
}
kawa
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish();
}
Wyskakujące okienko z miejscem docelowym
Aby usunąć miejsca docelowe z listy wstecznej podczas przechodzenia z jednego miejsca docelowego do drugiego, dodaj argument popUpTo() do powiązanego wywołania funkcji navigate(). popUpTo() nakazuje bibliotece Navigation usunięcie niektórych miejsc docelowych ze stosu wstecznego w ramach wywołania funkcji navigate(). Wartość parametru to identyfikator miejsca docelowego na stosie wstecznym. Identyfikator może być liczbą całkowitą id lub ciągiem znaków route.
Możesz dodać argument do parametru inclusive o wartości true, aby wskazać, że miejsce docelowe określone w parametrze popUpTo() powinno również zostać usunięte ze stosu wstecznego.
Aby zaimplementować to programowo, przekaż wartość popUpTo() do parametru navigate() w ramach parametru NavOptions z parametrem inclusive ustawionym na true. Działa to zarówno w przypadku funkcji Compose, jak i widoków.
Zapisywanie stanu podczas wyświetlania
Gdy używasz popUpTo do przejścia do miejsca docelowego, możesz opcjonalnie zapisać stos wsteczny i stany wszystkich miejsc docelowych usuniętych ze stosu wstecznego. Możesz wtedy przywrócić stos wsteczny i miejsca docelowe, gdy później przejdziesz do tego miejsca docelowego. Dzięki temu możesz zachować stan danego miejsca docelowego i mieć wiele list wstecz.
Aby to zrobić programowo, podczas dodawania popUpTo do opcji nawigacji określ saveState = true.
W opcjach nawigacji możesz też określić restoreState = true, aby automatycznie przywrócić stos wsteczny i stan powiązany z miejscem docelowym.
Przykład:
navController.navigate(
route = route,
navOptions = navOptions {
popUpTo<A>{ saveState = true }
restoreState = true
}
)
Aby włączyć zapisywanie i przywracanie stanu w formacie XML, zdefiniuj popUpToSaveState jako true
i restoreState jako true w odpowiednim pliku action.
Przykładowy komunikat
Poniżej znajdziesz kompletny przykład tego samego w 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")
}
}
Możesz też bardziej szczegółowo zmienić sposób wywoływania 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 nawigacji z opcjami.
Przykład w formacie XML
Oto przykład właściwości popUpTo w XML z użyciem 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"/>
Wyświetlanie za pomocą działań
Podczas nawigacji za pomocą działania możesz opcjonalnie usunąć dodatkowe miejsca docelowe ze stosu wstecznego. Jeśli na przykład aplikacja ma początkowy proces logowania, po zalogowaniu się użytkownika usuń wszystkie miejsca docelowe związane z logowaniem ze stosu wstecznego, aby przycisk Wstecz nie przenosił użytkowników z powrotem do procesu logowania.
Materiały dodatkowe
Więcej informacji znajdziesz na tych stronach:
- Nawigacja cykliczna: dowiedz się, jak uniknąć przepełnienia stosu wstecznego w przypadku cyklicznych przepływów nawigacji.
- Miejsca docelowe w oknie: dowiedz się, jak miejsca docelowe w oknie wpływają na zarządzanie stosem wstecznym.