Jetpack Compose & Navigation:问题在嵌套图中共享 ViewModel

chr*_*gue 9 android android-jetpack-navigation android-jetpack-compose dagger-hilt

根据这个示例,我在嵌套导航图中实现了共享 viewModel。

设置

嵌套图:

private fun NavGraphBuilder.accountGraph(navController: NavHostController) {
   navigation(
      startDestination = "main",
      route = "account") {

       composable("main") {
          val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
          //... ui ...
       }

       composable("login") {
          val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
          //... ui ...
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

导航主机:

@Composable
private fun NavHost(navController: NavHostController, modifier: Modifier = Modifier){
   NavHost(
      navController = navController,
      startDestination = MainScreen.Home.route,
      modifier = modifier
   ) {
      composable("home") { HomeScreen(hiltViewModel()) }
      composable("otherRoute") { OtherScreen(hiltViewModel()) }
      accountGraph(navController)
   }
}
Run Code Online (Sandbox Code Playgroud)

底部导航栏:

@Composable
private fun ButtonNav(navController: NavHostController) {
   BottomNavigation {
      val navBackStackEntry by navController.currentBackStackEntryAsState()
      val currentDestination = navBackStackEntry?.destination

      items.forEach { screen ->
         BottomNavigationItem(
            icon = { ... },
            label = { ... },
            selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
            onClick = {
               navController.navigate(screen.route) {

                  // Pop up to the start destination of the graph to
                  // avoid building up a large stack of destinations
                  // on the back stack as users select items
                  navController.graph.startDestinationRoute?.let { route ->
                     popUpTo(route) { saveState = true }
                  }

                  // Avoid multiple copies of the same destination when
                  // re-selecting the same item
                  launchSingleTop = true

                  // Restore state when re-selecting a previously selected item
                  restoreState = true
               }
            }
         )
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

问题

通过此设置,如果我导航到“帐户”(嵌套图)并返回到任何其他路线,我会收到错误:

java.lang.IllegalArgumentException: No destination with route account is on the NavController's back stack. The current destination is Destination(0x78dd8526) route=otherRoute
Run Code Online (Sandbox Code Playgroud)

假设/研究结果

底部导航项

当我删除 onClick 时,没有发生异常popUpTo(route)。但后来我得到了一大堆。

backStackEntry 的生命周期

看看以下内容:

//...
composable("main") { backStackEntry ->
   val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
   //... ui ...
}
//...
Run Code Online (Sandbox Code Playgroud)

我发现当向后导航时,剩下的可组合项将被重组,但在这种情况下, backStackEntry 接缝有另一个,lifecycle.currentState因为如果我像这样包装整个可组合项:

//...
composable("main") { backStackEntry ->
  if(backStackEntry.lifecycle.currentState == Lifecycle.State.RESUMED){
     val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
     //... ui ...
  }
}
//...
Run Code Online (Sandbox Code Playgroud)

...异常没有发生。当我看到官方示例有类似的解决方法时,我想到了生命周期问题的想法。

概括

我实际上不知道我是否做错了什么或者我是否错过了这里的概念。我可以将生命周期检查解决方法落实到位,但这真的符合预期吗?除此之外,我没有在文档中找到任何关于此的提示。

有人知道如何以正确的方式解决这个问题吗?

问候,克里斯

Alb*_*o97 1

导航组件存在问题。v2.4.0-alpha08 已为我修复了该问题