我想分享一个视图模型之间的许多可组合。就像我们如何在活动中的片段之间共享一个视图模型一样。
但当我尝试这个
setContent {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
navigation(startDestination = "username", route = "login") {
// FIXME: I get an error here
val viewModel: LoginViewModel = viewModel()
composable("username") { ... }
composable("password") { ... }
composable("registration") { ... }
}
}
}我犯了个错误
@Composable调用只能在@Composable函数的上下文中发生
需要
几乎相似解
发布于 2021-10-20 09:36:56
解决方案1
(复制自文档)
导航回堆栈不仅为每个单独的目标存储一个NavBackStackEntry,而且还存储包含单个目的地的每个父导航图。这使您能够检索到导航图的作用域的
NavBackStackEntry。导航图形范围的NavBackStackEntry提供了一种创建导航图作用域的ViewModel的方法,使您能够在图形的目的地之间共享UI相关的数据。任何以这种方式创建的ViewModel对象都会一直运行,直到相关的NavHost及其ViewModelStore被清除,或者导航图从后台堆栈中弹出。
这意味着我们可以使用NavBackStackEntry获取我们所在的导航图的范围,并将其作为ViewModelStoreOwner来获取该范围的视图模型。
将其添加到每个可组合的BackStackEntry中,以获得login的ViewModelStoreOwner,然后将其作为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
复制自安汉尼巴洛克答案
这也可以使用扩展来实现。
@Composable
fun <reified VM : ViewModel> NavBackStackEntry.parentViewModel(
navController: NavController
): VM {
// First, get the parent of the current destination
// This always exists since every destination in your graph has a parent
val parentId = destination.parent!!.id
// Now get the NavBackStackEntry associated with the parent
val parentBackStackEntry = navController.getBackStackEntry(parentId)
// And since we can't use viewModel(), we use ViewModelProvider directly
// to get the ViewModel instance, using the lifecycle-viewmodel-ktx extension
return ViewModelProvider(parentBackStackEntry).get()
}navigate(secondNestedRoute, startDestination = nestedStartRoute) {
composable(route) {
val loginViewModel: LoginViewModel = it.parentViewModel(navController)
}
}https://stackoverflow.com/questions/69642441
复制相似问题