In den folgenden Abschnitten werden Strategien zum Speichern des Back Stacks und des Status beschrieben, der mit Einträgen im Back Stack verknüpft ist.
Back Stack speichern
Damit die Nutzerfreundlichkeit hoch bleibt, muss der Navigationsstatus Ihrer App über verschiedene Lifecycle-Events hinweg beibehalten werden, einschließlich Konfigurationsänderungen und Prozessbeendigung. In Navigation 3 verwalten Sie Ihren Back Stack selbst. Es gibt also keine strengen Richtlinien dafür, wie Sie ihn erstellen oder speichern sollten. Navigation 3 bietet jedoch eine praktische Methode, mit der Sie einen speicherbaren Back Stack erhalten: rememberNavBackStack.
rememberNavBackStack verwenden
Die zusammensetzbare Funktion rememberNavBackStack ist so konzipiert, dass sie einen Back Stack erstellt, der auch bei Konfigurationsänderungen und Prozessbeendigungen erhalten bleibt.
Damit rememberNavBackStack korrekt funktioniert, muss jeder Schlüssel im Back Stack bestimmte Anforderungen erfüllen:
NavKey-Schnittstelle implementieren: Jeder Schlüssel im Back Stack muss dieNavKey-Schnittstelle implementieren. Diese dient als Markierungsschnittstelle, die der Bibliothek signalisiert, dass der Schlüssel gespeichert werden kann.- Mit der Annotation
@Serializableversehen: Zusätzlich zur Implementierung vonNavKeymüssen Ihre Schlüsselklassen und -objekte mit der Annotation@Serializablegekennzeichnet sein.
Das folgende Snippet zeigt eine korrekte Implementierung von rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
Back Stack mit Untertypen von NavKey merken
Die zusammensetzbare Funktion rememberNavBackStack gibt ein NavBackStack<NavKey> zurück.
Wenn Ihre App einen eigenen Untertyp von NavKey definiert, von dem alle Schlüssel erben, können Sie diese Typisierung beibehalten, indem Sie eine benutzerdefinierte „remember“-Funktion implementieren:
@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) }
Weitere Beispiele, einschließlich des Umgangs mit offenem Polymorphismus, finden Sie unter NavBackStackSamples.
Alternative: In einem ViewModel speichern
Eine weitere Möglichkeit, den Back Stack zu verwalten, besteht darin, ihn in einem ViewModel zu speichern.
Wenn Sie einen ViewModel oder einen anderen benutzerdefinierten Speicher verwenden, müssen Sie Folgendes tun, um die Persistenz bei Prozessbeendigung zu gewährleisten:
- Schlüssel müssen serialisierbar sein: Genau wie bei
rememberNavBackStackmüssen Ihre Navigationsschlüssel serialisierbar sein. - Serialisierung und Deserialisierung manuell verwalten: Sie sind dafür verantwortlich, die serialisierte Darstellung jedes Schlüssels manuell im nichtflüchtigen Speicher (z.B.
SharedPreferences, einer Datenbank oder einer Datei) zu speichern und von dort zu deserialisieren, wenn Ihre App in den Hintergrund wechselt oder wiederhergestellt wird.
ViewModel-Instanzen auf NavEntry-Objekte beschränken
ViewModels werden verwendet, um den UI-bezogenen Status bei Konfigurationsänderungen wie Bildschirmdrehungen beizubehalten. Standardmäßig sind ViewModels auf die nächstgelegene ViewModelStoreOwner beschränkt, die in der Regel Ihre Activity oder Fragment ist.
Möglicherweise möchtest du einen ViewModel jedoch auf einen bestimmten NavEntry (d.h. einen bestimmten Bildschirm oder ein bestimmtes Ziel) im Back Stack beschränken, anstatt auf den gesamten Activity. So wird sichergestellt, dass der Status des ViewModel nur beibehalten wird, solange das jeweilige NavEntry Teil des Back Stacks ist, und gelöscht wird, wenn das NavEntry entfernt wird.
Die Add-on-Bibliothek androidx.lifecycle:lifecycle-viewmodel-navigation3 bietet eine NavEntryDecorator, die dies erleichtert. Dieser Decorator stellt für jede NavEntry eine ViewModelStoreOwner bereit. Wenn Sie ein ViewModel innerhalb des Inhalts eines NavEntry erstellen (z.B. mit viewModel() in Compose), wird es automatisch auf den Schlüssel dieses bestimmten NavEntry im Back Stack beschränkt. Das bedeutet, dass das ViewModel erstellt wird, wenn das NavEntry dem Back Stack hinzugefügt wird, und gelöscht wird, wenn es entfernt wird.
So verwenden Sie NavEntryDecorator, um den Bereich von ViewModels auf NavEntrys festzulegen:
- Fügen Sie der Datei
app/build.gradle.ktsdie Abhängigkeitandroidx.lifecycle:lifecycle-viewmodel-navigation3hinzu. - Fügen Sie beim Erstellen eines
NavDisplayden Standard-rememberSaveableStateHolderNavEntryDecorator()zur Liste derentryDecoratorshinzu. - Fügen Sie
rememberViewModelStoreNavEntryDecorator()zur Liste derentryDecoratorshinzu.
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 { }, )