簡體   English   中英

Jetpack Compose & Navigation:問題在嵌套圖中共享 ViewModel

[英]Jetpack Compose & Navigation: Problems share ViewModel in nested graph

根據這個例子,我在嵌套導航圖中實現了共享視圖模型。

設置

嵌套圖:

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 ...
       }
   }
}

導航主機:

@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)
   }
}

底部導航欄:

@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
               }
            }
         )
      }
   }
}

問題

使用此設置,如果我導航到“帳戶”(嵌套圖)並返回到任何其他路線,我會收到錯誤消息:

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

假設/研究結果

底部導航項

當我刪除popUpTo(route) onClick 時沒有發生異常。 但后來我得到了一大堆。

backStackEntry 的生命周期

看看以下內容:

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

我發現當導航回來時,剩下的可組合將被重新組合,但在這種情況下,backStackEntry 接縫有另一個lifecycle.currentState .currentState,因為如果我像這樣包裝整個可組合:

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

...沒有發生異常。 當我看到官方示例有類似的解決方法時,我想到了生命周期問題。

概括

我實際上不知道我是否做錯了什么,或者我是否在這里錯過了一個概念。 我可以將生命周期檢查解決方法落實到位,但這真的符合預期嗎? 除此之外,我在文檔中沒有找到任何關於此的提示。

有誰知道如何以正確的方式解決這個問題?

問候, 克里斯

導航組件存在問題 它已通過 v2.4.0-alpha08 為我修復

這就是您現在的做法,但請確保您擁有最新的撰寫導航人工制品:

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

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

       composable("login") {
          val parentEntry = remember {
            navController.getBackstackEntry("account")
          }
          val vm = hiltViewModel<AccountViewModel(parentEntry)
          //... ui ...
       }
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM