eim*_*mer 5 android android-jetpack-compose jetpack-compose-navigation compose-recomposition
在 Android 中,我经常想要导航以响应 ViewModel 的状态更改。(例如,成功的身份验证会触发导航到用户的主屏幕。)
最佳实践是从 ViewModel 内触发导航吗?是否有有意的机制来触发可组合项中的导航以响应 ViewModel 状态更改?
使用 Jetpack Compose 处理此用例的过程并不明显。如果我尝试类似以下示例的操作,将会发生导航,但我导航到的目的地将无法正常运行。我相信这是因为在调用导航之前不允许完成原始的可组合函数。
// Does not behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
navController.navigate("/gameScreen")
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 LaunchedEffect ,我确实会观察到正确的行为,如下所示:
// Does behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
LaunchedEffect(key1 = "test") {
navController.navigate("$/gameScreen")
}
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
它是否正确?LaunchedEffect 的文档说明如下,但我并不是 100% 清楚其含义:
当 LaunchedEffect 进入组合时,它将启动块到组合的 CoroutineContext 中。当 LaunchedEffect 用不同的 key1、key2 或 key3 重新组合时,协程将被取消并重新启动。当 LaunchedEffect 离开合成时,协程将被取消。
这段代码
// Does not behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
navController.navigate("/gameScreen")
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
其行为不正确很可能会导致这样的问题,解决该问题的方法之一就是这样做
// Does behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
LaunchedEffect(key1 = "test") {
navController.navigate("$/gameScreen")
}
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
其行为正确,因为假设它在下一个组合传递中不会改变,则LaunchedEffect保证只执行一次,否则它将在其可组合范围的每次更新时继续执行。compositionkey
我建议不仅根据建议的组件考虑“正确”,还要考虑如何避免像我提供的链接这样的导航陷阱。
如果它来自某个或某些流排放并不重要ViewModel,但组合中安全导航的想法(据我所知)是确保导航调用仅发生在永远不会重新生成的块中执行成功re-compositions,这也受到上面第一种代码的影响。
| 归档时间: |
|
| 查看次数: |
1319 次 |
| 最近记录: |