W kolejnych sekcjach opisujemy strategie zapisywania listy wstecznej i przechowywania stanu powiązanego z elementami na tej liście.
Zapisywanie listy wstecznej
Zapewnienie, że stan nawigacji aplikacji jest zachowywany w różnych zdarzeniach cyklu życia, w tym w przypadku zmian konfiguracji i śmierci procesu, ma kluczowe znaczenie dla wygody użytkowników. W Navigation 3 masz pełną kontrolę nad stosem wstecznym, więc nie ma ścisłych wytycznych dotyczących jego tworzenia ani zapisywania. Nawigacja 3 udostępnia jednak wygodną metodę, która zapewnia możliwość zapisania stosu wstecznego: rememberNavBackStack.
Używaj klawisza rememberNavBackStack
Funkcja typu „composable” rememberNavBackStack służy do tworzenia stosu wstecznego, który zachowuje trwałość w przypadku zmian konfiguracji i śmierci procesu.
Aby funkcja rememberNavBackStack działała prawidłowo, każdy klucz w stosie wstecznym musi spełniać określone wymagania:
- Zaimplementuj interfejs
NavKey: każdy klucz na stosie wstecznym musi implementować interfejsNavKey. Jest to interfejs znacznika, który sygnalizuje bibliotece, że klucz można zapisać. - Mieć adnotację
@Serializable: oprócz wdrożeniaNavKeykluczowe klasy i obiekty muszą być oznaczone adnotacją@Serializable.
Poniższy fragment kodu pokazuje prawidłową implementację elementu rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
Zapamiętaj stos wsteczny z podtypami NavKey
Funkcja typu „composable” rememberNavBackStack zwraca NavBackStack<NavKey>.
Jeśli aplikacja definiuje własny podtyp NavKey, z którego dziedziczą wszystkie jej klucze, możesz zachować to typowanie, implementując niestandardową funkcję remember w ten sposób:
@Serializable sealed interface MyAppNavKey : NavKey @Serializable data object ScreenA: MyAppNavKey @Serializable data class ScreenB(val id: String): MyAppNavKey @Composable fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> { return rememberSerializable(serializer = serializer()) { NavBackStack(*elements) } } @Composable fun MyApp() { // defaultNavBackStack is NavBackStack<NavKey> val defaultNavBackStack = rememberNavBackStack(ScreenA) // myAppNavBackStack is NavBackStack<MyAppNavKey> val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA) }
Więcej przykładów, w tym informacji o tym, jak obsługiwać otwarty polimorfizm, znajdziesz w NavBackStackSamples.
Alternatywa: przechowywanie w ViewModel
Innym sposobem zarządzania stosem wstecznym jest przechowywanie go w ViewModel.
Aby zapewnić trwałość po śmierci procesu podczas korzystania z atrybutu ViewModel lub dowolnego innego niestandardowego miejsca na dane, musisz:
- Upewnij się, że klucze można serializować: podobnie jak w przypadku
rememberNavBackStack, klucze nawigacyjne muszą być serializowalne. - Ręczne obsługiwanie serializacji i deserializacji: musisz ręcznie zapisywać w pamięci trwałej (np.
SharedPreferences, w bazie danych lub w pliku) zserializowaną reprezentację każdego klucza i deserializować ją z tej pamięci, gdy aplikacja przechodzi w tło lub jest przywracana.
Zakres od ViewModel s do NavEntry s
ViewModels służą do zachowywania stanu interfejsu w przypadku zmian konfiguracji, takich jak obracanie ekranu. Domyślnie ViewModels są ograniczone do najbliższego ViewModelStoreOwner, którym jest zwykle Activity lub Fragment.
Możesz jednak ograniczyć zakres ViewModel do konkretnego NavEntry (czyli konkretnego ekranu lub miejsca docelowego) na stosie wstecznym, a nie do całego Activity. Dzięki temu stan elementu ViewModel jest zachowywany tylko wtedy, gdy dany element NavEntry jest częścią stosu wstecznego, i jest czyszczony, gdy element NavEntry zostanie usunięty ze stosu.
Biblioteka dodatku androidx.lifecycle:lifecycle-viewmodel-navigation3 udostępnia NavEntryDecorator, który to ułatwia. Ten dekorator udostępnia ViewModelStoreOwner dla każdego NavEntry. Gdy utworzysz ViewModel w treści NavEntry (np. za pomocą viewModel() w funkcji Compose), zostanie ono automatycznie ograniczone do klucza tego konkretnego elementu NavEntry na stosie wstecznym. Oznacza to, że element ViewModel jest tworzony, gdy element NavEntry jest dodawany do stosu wstecznego, i usuwany, gdy jest z niego usuwany.
Aby użyć NavEntryDecorator do określania zakresu ViewModel w NavEntry, wykonaj te czynności:
- Dodaj zależność
androidx.lifecycle:lifecycle-viewmodel-navigation3do plikuapp/build.gradle.kts. - Dodaj domyślny adres
rememberSaveableStateHolderNavEntryDecorator()do listyentryDecoratorspodczas tworzeniaNavDisplay. - Dodaj
rememberViewModelStoreNavEntryDecorator()do listyentryDecorators.
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSaveableStateHolderNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )