W kolejnych sekcjach opisujemy strategie zapisywania listy wstecznej i przechowywania stanu powiązanego z elementami na tej liście.
Zapisywanie listy poprzednich ekranów
Zapewnienie, że stan nawigacji aplikacji jest zachowywany w różnych zdarzeniach cyklu życia, w tym w przypadku zmian konfiguracji i zakończenia procesu, ma kluczowe znaczenie dla wygody użytkowników. W Navigation 3 masz własny stos wsteczny, 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żyj konta rememberNavBackStack
Funkcja z możliwością łączenia rememberNavBackStack służy do tworzenia stosu wstecznego, który zachowuje trwałość przy zmianach konfiguracji i zakończeniu 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 w 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 zachować trwałość po zakończeniu 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.
Określanie zakresu instancji ViewModel na obiekty NavEntry
ViewModels służą do zachowywania stanu związanego z interfejsem w przypadku zmian konfiguracji, takich jak obracanie ekranu. Domyślnie ViewModels są ograniczone do najbliższego ViewModelStoreOwner, czyli zwykle Activity lub Fragment.
Możesz jednak ograniczyć zakres ViewModel do konkretnego NavEntry (czyli konkretnego ekranu lub miejsca docelowego) na liście wstecznej, 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 dodatków androidx.lifecycle:lifecycle-viewmodel-navigation3 udostępnia NavEntryDecorator, który to ułatwia. Ten dekorator udostępnia ViewModelStoreOwner dla każdego elementu NavEntry. Gdy utworzysz ViewModel w treści NavEntry (np. za pomocą viewModel() w funkcji Compose), zostanie on automatycznie ograniczony 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 element
rememberSaveableStateHolderNavEntryDecorator()do listyentryDecoratorspodczas tworzenia elementuNavDisplay. - 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 { }, )