Zapisywanie stanu nawigacji i zarządzanie nim

W następnych sekcjach opisaliśmy strategie zapisywania stosu i zapisywania stanu powiązanego z elementami w stosie.

Zapisz stos wywołań

Zapewnienie spójności stanu nawigacji w aplikacji w różnych zdarzeniach cyklu życia, w tym w przypadku zmian konfiguracji i zakończenia procesu, jest kluczowe dla zapewnienia dobrego wrażenia korzystania z aplikacji. W Nawigacji 3 masz kontrolę nad warstwą wsteczną, więc nie ma ścisłych wytycznych dotyczących jej tworzenia ani zapisywania. Nawigacja 3 oferuje jednak wygodną metodę, która umożliwia zapisanie ścieżki wstecz:rememberNavBackStack.

Używaj klawisza rememberNavBackStack

Funkcja kompozytowa rememberNavBackStack została zaprojektowana tak, aby tworzyć warstwę pośrednią, która zachowuje trwałość pomimo zmian konfiguracji i zakończenia działania procesu.

Aby rememberNavBackStack działał prawidłowo, każdy klucz w grupie musi spełniać określone wymagania:

  • Zaimplementuj interfejs NavKey: każdy klucz w grupie poprzednich kluczy musi implementować interfejs NavKey. Jest to interfejs znacznika, który sygnalizuje bibliotece, że klucz można zapisać.
  • Zaimplementuj adnotację @Serializable: oprócz zaimplementowania NavKey klasy i obiekty kluczy muszą być oznaczone adnotacją @Serializable.

Ten fragment kodu pokazuje prawidłową implementację funkcji rememberNavBackStack:

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

Alternatywa: przechowywanie w ViewModel

Innym sposobem zarządzania stosem wstecz jest przechowywanie go w ViewModel. Aby zapewnić trwałość danych po śmierci procesu przy użyciu usługi ViewModel lub innego niestandardowego miejsca do przechowywania, musisz:

  • Upewnij się, że klucze można zserializować: podobnie jak w przypadku rememberNavBackStack, klucze nawigacyjne muszą być możliwe do zserializowania.
  • Ręczne zarządzanie serializacją i deserializacją: musisz ręcznie zapisać serializowane reprezentacje poszczególnych kluczy w trwałym miejscu przechowywania i zapisać je w tym samym miejscu (np. SharedPreferences, bazy danych lub pliku) podczas przełączania aplikacji na tło lub przywracania.

Ograniczenie zakresu do ViewModel sNavEntry

ViewModels służą do zachowania stanu związanego z interfejsem podczas zmian konfiguracji, takich jak obracanie ekranu. Domyślnie ViewModels są ograniczone do najbliższego ViewModelStoreOwner, którym zwykle jest Activity lub Fragment.

Możesz jednak ograniczyć zakres ViewModel do konkretnego NavEntry (czyli konkretnego ekranu lub miejsca docelowego) w grupie elementów na poprzednim poziomie, a nie do wszystkich elementów tej grupy.Activity Dzięki temu stan ViewModel jest zachowany tylko wtedy, gdy ten konkretny element NavEntry znajduje się na stosie, a usuwany jest, gdy NavEntry zostaje usunięty.

Biblioteka dodatków androidx.lifecycle:lifecycle-viewmodel-navigation3 udostępnia NavEntryDecorator, która ułatwia to zadanie. Ten dekorator udostępnia element ViewModelStoreOwner dla każdego elementu NavEntry. Gdy utworzysz ViewModel w ramach treści NavEntry (np. używając viewModel() w sekcji Redagowanie), zostanie on automatycznie ograniczony do klucza NavEntry w bieżącym stosie. Oznacza to, że ViewModel jest tworzony, gdy NavEntry jest dodawany do stosu, i czyszczony, gdy jest usuwany.

Aby użyć NavEntryDecorator do określenia zakresu ViewModel w przypadku NavEntry, wykonaj te czynności:

  1. Dodaj zależność androidx.lifecycle:lifecycle-viewmodel-navigation3 do pliku app/build.gradle.kts.
  2. Dodaj rememberSavedStateNavEntryDecorator() do listy entryDecorators podczas tworzenia NavDisplay.
  3. Dodaj innych dekoratorów do NavDisplay.

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSceneSetupNavEntryDecorator(),
        rememberSavedStateNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)