In den folgenden Abschnitten werden Strategien zum Speichern des Backstacks und zum Speichern des mit Einträgen im Backstack verknüpften Status beschrieben.
Backstack speichern
Es ist wichtig, dass der Navigationsstatus Ihrer App bei verschiedenen Lebenszyklusereignissen beibehalten wird, einschließlich Konfigurationsänderungen und Prozessbeendigung, um eine gute Nutzererfahrung zu gewährleisten. In Navigation 3 verwalten Sie den Backstack selbst. Es gibt daher keine strengen Richtlinien dazu, wie Sie ihn erstellen oder speichern sollten. Navigation 3 bietet jedoch eine praktische Methode, mit der Sie einen speicherbaren Backstack erstellen können: rememberNavBackStack.
rememberNavBackStack verwenden
Die zusammensetzbare Funktion rememberNavBackStack wurde entwickelt, um einen Backstack zu erstellen, der Konfigurationsänderungen und das Beenden von Prozessen überdauert.
Damit rememberNavBackStack richtig funktioniert, muss jeder Schlüssel in Ihrem Backstack bestimmte Anforderungen erfüllen:
NavKey-Schnittstelle implementieren: Jeder Schlüssel im Backstack muss dieNavKey-Schnittstelle implementieren. Dies dient als Markierungsschnittstelle, die der Bibliothek signalisiert, dass der Schlüssel gespeichert werden kann.@Serializable-Annotation: Zusätzlich zur Implementierung vonNavKeymüssen Ihre Schlüsselklassen und -objekte mit der@Serializable-Annotation gekennzeichnet werden.
Das folgende Snippet zeigt eine korrekte Implementierung von rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
Einen Backstack mit Untertypen von NavKey erstellen
Die komponierbare Funktion rememberNavBackStack gibt ein NavBackStack<NavKey> zurück.
Wenn in Ihrer App ein eigener Untertyp von NavKey definiert ist, von dem alle Schlüssel abgeleitet werden, können Sie diesen Typ 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, auch zum Umgang mit offener Polymorphie, finden Sie unter NavBackStackSamples.
Alternative: Speichern in einer ViewModel
Eine weitere Möglichkeit, den Backstack zu verwalten, besteht darin, ihn in einem ViewModel zu speichern.
Wenn Sie bei Verwendung von ViewModel oder einem anderen benutzerdefinierten Speicher die Persistenz über das Beenden von Prozessen hinweg beibehalten möchten, müssen Sie Folgendes tun:
- Schlüssel müssen serialisierbar sein: Wie bei
rememberNavBackStackmüssen Ihre Navigationsschlüssel serialisierbar sein. - Serialisierung und Deserialisierung manuell verarbeiten: Sie sind dafür verantwortlich, die serialisierte Darstellung jedes Schlüssels manuell im persistenten Speicher (z.B.
SharedPreferences, einer Datenbank oder einer Datei) zu speichern und daraus zu deserialisieren, wenn Ihre App in den Hintergrund verschoben oder wiederhergestellt wird.
Bereich von ViewModel bis NavEntry Sekunden
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, in der Regel auf Ihre Activity oder Fragment.
Möglicherweise möchten Sie jedoch einen ViewModel auf einen bestimmten NavEntry (d.h. einen bestimmten Bildschirm oder eine bestimmte Zielanwendung) im Backstack und nicht auf das gesamte Activity beschränken. So wird sichergestellt, dass der Status von ViewModel nur beibehalten wird, solange dieser NavEntry Teil des Backstacks ist. Er wird gelöscht, wenn der NavEntry entfernt wird.
Die Add-on-Bibliothek androidx.lifecycle:lifecycle-viewmodel-navigation3 bietet eine NavEntryDecorator, die dies erleichtert. Dieser Dekorator stellt für jede NavEntry ein ViewModelStoreOwner bereit. Wenn Sie ein ViewModel im Inhalt eines NavEntry erstellen (z.B. mit viewModel() in Compose), wird es automatisch auf den Schlüssel dieses NavEntry im Backstack beschränkt. Das bedeutet, dass das ViewModel erstellt wird, wenn das NavEntry dem Backstack hinzugefügt wird, und gelöscht wird, wenn es entfernt wird.
So verwenden Sie NavEntryDecorator, um ViewModels auf NavEntrys einzugrenzen:
- Fügen Sie der Datei
app/build.gradle.ktsdie Abhängigkeitandroidx.lifecycle:lifecycle-viewmodel-navigation3hinzu. - Fügen Sie der Liste der
entryDecoratorsdas Standard-rememberSaveableStateHolderNavEntryDecorator()hinzu, wenn Sie einNavDisplayerstellen. - Fügen Sie
rememberViewModelStoreNavEntryDecorator()der 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 { }, )