以下部分介绍了用于保存返回堆栈和存储与返回堆栈中的条目关联的状态的策略。
保存返回堆栈
确保应用的导航状态在各种生命周期事件(包括配置更改和进程终止)中保持不变对于良好的用户体验至关重要。在 Navigation 3
中,您拥有自己的返回堆栈,因此没有关于如何创建或保存返回堆栈的严格指南。不过,Navigation 3 确实提供了一种便捷方法,可为您提供可保存的返回堆栈:
rememberNavBackStack。
使用 rememberNavBackStack
rememberNavBackStack 可组合函数旨在创建一个在配置更改和进程终止后仍保持不变的返回堆栈。
为了让 rememberNavBackStack 正常运行,返回堆栈中的每个键都必须遵循特定要求:
- 实现
NavKey接口:返回堆栈中的每个键都必须实现NavKey接口。此接口充当标记接口,向库发出键可以保存的信号。 - 具有
@Serializable注解:除了实现NavKey之外, 您的键类和对象还必须使用@Serializable注解进行标记。
以下代码段展示了 rememberNavBackStack 的正确实现:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
使用 NavKey 的子类型记住返回堆栈
rememberNavBackStack 可组合函数会返回 NavBackStack<NavKey>。
如果您的应用定义了自己的
NavKey 子类型,并且其所有键都继承自该子类型,则可以通过实现自定义 remember 函数来保留该类型,如下所示:
@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) }
如需查看更多示例(包括如何处理开放多态性),请参阅
NavBackStackSamples。
替代方案:存储在 ViewModel 中
管理返回堆栈的另一种方法是将其存储在 ViewModel 中。如需在使用 ViewModel 或任何其他自定义存储空间时在进程终止后保持不变,您需要:
- 确保您的键是可序列化的:与
rememberNavBackStack一样, 您的导航键必须是可序列化的。 - 手动处理序列化和反序列化:当您的应用进入后台或恢复时,您负责
手动将每个键的序列化表示形式保存到永久性存储空间(例如
SharedPreferences、 数据库或文件),并从中反序列化。
将 ViewModel 的作用域限定为 NavEntry
ViewModels 用于在配置更改(例如屏幕旋转)时保留与界面相关的状态。默认情况下,ViewModels 的作用域限定为最近的
ViewModelStoreOwner,通常是您的 Activity 或 Fragment。
不过,您可能希望将 ViewModel 的作用域限定为返回堆栈中的特定 NavEntry(即特定屏幕或目标位置),而不是整个
Activity。这样可确保仅当该特定 NavEntry 是返回堆栈的一部分时,ViewModel 的状态才会保留,并且在弹出
NavEntry 时清除。
androidx.lifecycle:lifecycle-viewmodel-navigation3 附加库提供了一个 NavEntryDecorator,可帮助实现此目的。此装饰器为每个
NavEntry 提供了一个 ViewModelStoreOwner。当您在 NavEntry 的内容中创建
ViewModel(例如,在 Compose 中使用 viewModel())时,它会自动限定为返回堆栈中该特定 NavEntry 的键。这意味着,当
NavEntry 添加到返回堆栈时,系统会创建 ViewModel,并在移除 NavEntry 时清除 ViewModel。
如需使用 NavEntryDecorator 将 ViewModel 的作用域限定为 NavEntry,请按
以下步骤操作:
- 将
androidx.lifecycle:lifecycle-viewmodel-navigation3依赖项添加到app/build.gradle.kts文件中。 - 将默认的
rememberSaveableStateHolderNavEntryDecorator()添加到entryDecorators列表中,在构建NavDisplay时。 - 将
rememberViewModelStoreNavEntryDecorator()添加到entryDecorators列表中。
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 { }, )