android - Jetpack Compose 中的作用域状态

标签 android android-viewmodel android-navigation android-jetpack-compose

在所有应用程序中,总会有这三个状态范围:
States
使用 Compose,可以通过以下方式实现“每屏幕状态”:

NavHost(navController, startDestination = startRoute) {
    ...
    composable(route) {
       ...
       val perScreenViewModel = viewModel()  // This will be different from
    }
    composable(route) {
       ...
       val perScreenViewModel = viewModel()  // this instance
    }
    ...
}
“应用程序状态”可以通过以下方式实现:
val appStateViewModel = viewModel()
NavHost(navController, startDestination = startRoute) {
    ...
}
但是“作用域状态”呢?我们如何在 Compose 中实现它?

最佳答案

这正是navigation graph scoped view models用于。
这包括两个步骤:

  • 寻找 NavBackStackEntry与要将 ViewModel 范围限定为的图形相关联
  • 把它传给 viewModel() .

  • 对于第 1 部分),您有两个选择。如果您知道导航图的路线(通常您应该知道),您可以使用 getBackStackEntry直接地:
    // Note that you must always use remember with getBackStackEntry
    // as this ensures that the graph is always available, even while
    // your destination is animated out after a popBackStack()
    val navigationGraphEntry = remember {
      navController.getBackStackEntry("graph_route")
    }
    val navigationGraphScopedViewModel = viewModel(navigationGraphEntry)
    
    但是,如果您想要更通用的东西,您可以使用目标本身中的信息检索返回堆栈条目 - 它的 parent :
    fun NavBackStackEntry.rememberParentEntry(): NavBackStackEntry {
      // First, get the parent of the current destination
      // This always exists since every destination in your graph has a parent
      val parentId = navBackStackEntry.destination.parent!!.id
    
      // Now get the NavBackStackEntry associated with the parent
      // making sure to remember it
      return remember {
        navController.getBackStackEntry(parentId)
      }
    }
    
    这使您可以编写如下内容:
    val parentEntry = it.rememberParentEntry()
    val navigationGraphScopedViewModel = viewModel(parentEntry)
    
    parent当您使用 nested navigation 时,目的地将等于简单导航图的根图,父级是图形的中间层之一:
    NavHost(navController, startDestination = startRoute) {
        ...
      navigation(startDestination = nestedStartRoute, route = nestedRoute) {
        composable(route) {
          // This instance will be the same
          val parentViewModel: YourViewModel = viewModel(it.rememberParentEntry())
        }
        composable(route) {
          // As this instance
          val parentViewModel: YourViewModel = viewModel(it.rememberParentEntry())
        }
      }
      navigation(startDestination = nestedStartRoute, route = secondNestedRoute) {
        composable(route) {
            // But this instance is different
          val parentViewModel: YourViewModel = viewModel(it.rememberParentEntry())
        }
      }
      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 = viewModel(it.rememberParentEntry())
      }
      ...
    }
    
    请注意,您不仅限于直接父级:每个父级导航图都可用于提供更大的范围。

    关于android - Jetpack Compose 中的作用域状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64955859/

    相关文章:

    android - 如何从 AbstractSavedStateViewModelFactory 动态设置包

    android - 以 viewModel 作为数据绑定(bind)变量重用 Fragments/Bottomsheets

    android - 从 jni (ndk) 创建大数组并将它们返回给 android

    java - 带有 GBoard 输入的 EditText 首字母大写

    android - viewModelScope 未取消

    android - 使用导航组件时如何设置对话框的目标 fragment

    android - 后退按钮将我带到启动器 Activity 而不是深层链接器 Activity

    android - 如何使用导航 Controller 设置抽屉导航并处理单个菜单项

    Android:是否可以让 Spanned 的部分文本在 TextView 中可聚焦?

    java - 程序在 ObjectInputStream 阻塞