解决方案1
(来源于文档)
导航后退堆栈存储了一个 NavBackStackEntry 不仅为每个单独的目标,还包括每个包含单独目标的父级导航图。这使您能够检索到作用域限定于导航图的 NavBackStackEntry
,从而创建一个关联到导航图的 ViewModel
,从而实现在导航图的目标之间共享UI相关数据。在此方式下创建的任何 ViewModel
对象生存期持续到关联的 NavHost
和其 ViewModelStore
被清除,或者导航图从后退堆栈弹出。
这意味着我们可以使用 NavBackStackEntry 获取所处导航图的范围,并将其用作 ViewModelStoreOwner
以获取该范围的视图模型。
在每个组合项中添加以下内容,以获取 login
的 BackStackEntry
,然后将其用作 ViewModelStoreOwner
以获取视图模型。
val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
因此,最终的代码更改为:
setContent {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
navigation(startDestination = "username", route = "login") {
composable("username") {
val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
...
}
composable("password") {
val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
...
}
composable("registration") {
val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
...
}
}
}
}
解决方案2
摘自 ianhanniballake 的回答
还可以使用扩展函数来实现:
- 获取当前作用域并获取或创建该作用域的视图模型
@Composable
fun <reified VM : ViewModel> NavBackStackEntry.parentViewModel(
navController: NavController
): VM {
val parentId = destination.parent!!.id
val parentBackStackEntry = navController.getBackStackEntry(parentId)
return ViewModelProvider(parentBackStackEntry).get()
}
- 接下来只需在你的导航图中使用此扩展程序
navigate(secondNestedRoute, startDestination = nestedStartRoute) {
composable(route) {
val loginViewModel: LoginViewModel = it.parentViewModel(navController)
}
}