首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在NavGraph组件之间共享视图模型(仅限于)

如何在NavGraph组件之间共享视图模型(仅限于)
EN

Stack Overflow用户
提问于 2021-10-20 08:08:55
回答 1查看 2.3K关注 0票数 6

我想分享一个视图模型之间的许多可组合。就像我们如何在活动中的片段之间共享一个视图模型一样。

但当我尝试这个

代码语言:javascript
复制
setContent {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        navigation(startDestination = "username", route = "login") {
            // FIXME: I get an error here
            val viewModel: LoginViewModel = viewModel()
            composable("username") { ... }
            composable("password") { ... }
            composable("registration") { ... }
        }
    }
}

我犯了个错误

@Composable调用只能在@Composable函数的上下文中发生

需要

  • 视图模型应该仅在NavGraph作用域中处于活动状态。
  • 当我走到另一条路线返回时,我应该初始化一个新的视图模型(这就是我在NavGraph中调用它的原因)

几乎相似解

  1. 菲利普·杜霍夫如何在撰写NavGraph中共享两个或多个Jetpack可组合的视图模型?问题的回答 但是在这种方法中,视图模型保留在启动它的活动的范围内,因此永远不会被垃圾收集。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-20 09:36:56

解决方案1

(复制自文档)

导航回堆栈不仅为每个单独的目标存储一个NavBackStackEntry,而且还存储包含单个目的地的每个父导航图。这使您能够检索到导航图的作用域的NavBackStackEntry。导航图形范围的NavBackStackEntry提供了一种创建导航图作用域的ViewModel的方法,使您能够在图形的目的地之间共享UI相关的数据。任何以这种方式创建的ViewModel对象都会一直运行,直到相关的NavHost及其ViewModelStore被清除,或者导航图从后台堆栈中弹出。

这意味着我们可以使用NavBackStackEntry获取我们所在的导航图的范围,并将其作为ViewModelStoreOwner来获取该范围的视图模型。

将其添加到每个可组合的BackStackEntry中,以获得loginViewModelStoreOwner,然后将其作为ViewModelStoreOwner来获取视图模型。

代码语言:javascript
复制
val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)

因此,最后的代码更改为

代码语言:javascript
复制
setContent {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        navigation(startDestination = "username", route = "login") {
            composable("username") { 
                val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
                val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
                ... 
            }
            composable("password") { 
                val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
                val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
                ... 
            }
            composable("registration") { 
                val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
                val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
                ... 
            }
        }
    }
}

解决方案2

复制自安汉尼巴洛克答案

这也可以使用扩展来实现。

  1. 获取当前作用域并获取或创建该作用域的视图模型。
代码语言:javascript
复制
@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()
}
  1. 然后,只需在导航图中使用这个扩展。
代码语言:javascript
复制
navigate(secondNestedRoute, startDestination = nestedStartRoute) {
  composable(route) {
    val loginViewModel: LoginViewModel = it.parentViewModel(navController)
  }
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69642441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档