Arc*_*nes 18 android android-navigation android-viewmodel android-jetpack-compose
使用 Compose,可以通过以下方式实现“每个屏幕状态”:
NavHost(navController, startDestination = startRoute) {
...
composable(route) {
...
val perScreenViewModel = viewModel() // This will be different from
}
composable(route) {
...
val perScreenViewModel = viewModel() // this instance
}
...
}
Run Code Online (Sandbox Code Playgroud)
“应用程序状态”可以通过以下方式实现:
val appStateViewModel = viewModel()
NavHost(navController, startDestination = startRoute) {
...
}
Run Code Online (Sandbox Code Playgroud)
但是对于“Scoped State”呢?我们如何在 Compose 中实现它?
ian*_*ake 18
这正是导航图作用域视图模型的用途。
虽然viewModel()API 不允许您直接访问导航图范围的 API(没有与 Fragment by navGraphViewModels()API等效的API),但您可以编写一个方法来执行此操作:
@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()
}
Run Code Online (Sandbox Code Playgroud)
使用Navigation Compose 1.0.0-alpha02 版本,您可以添加嵌套导航图,从而允许您编写如下图:
NavHost(navController, startDestination = startRoute) {
...
navigate(nestedRoute, startDestination = nestedStartRoute) {
composable(route) {
...
// This instance will be the same
val parentViewModel: YourViewModel = it.parentViewModel(navController)
}
composable(route) {
...
// As this instance
val parentViewModel: YourViewModel = it.parentViewModel(navController)
}
}
navigate(secondNestedRoute, startDestination = nestedStartRoute) {
composable(route) {
...
// But this instance is different
val parentViewModel: YourViewModel = it.parentViewModel(navController)
}
}
composable(route) {
...
// This is also different (the parent is the root graph)
// but the root graph has the same scope as the whole NavHost
// so this isn't particularly helpful
val parentViewModel: YourViewModel = it.parentViewModel(navController)
}
...
}
Run Code Online (Sandbox Code Playgroud)
请注意,您不仅限于直接父级:每个父级导航图都可用于提供更大的范围。
要检索范围为导航路线的实例ViewModel,请将目标根作为参数传递:
val loginBackStackEntry = remember { navController.getBackStackEntry("Parent") }
val loginViewModel: LoginViewModel = hiltViewModel(loginBackStackEntry)
Run Code Online (Sandbox Code Playgroud)
没有 Hilt 也可以完成同样的操作
val loginBackStackEntry = remember { navController.getBackStackEntry("Parent") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
Run Code Online (Sandbox Code Playgroud)
这实现了@ianhanniballake所实现的相同效果,但代码更少
注意:导航图有自己的route =“Parent”
完整代码示例
使用 Jetpack 撰写和导航的范围状态示例
val loginBackStackEntry = remember { navController.getBackStackEntry("Parent") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2047 次 |
| 最近记录: |