gpt4 book ai didi

android - 如何在 NavGraph 组件之间共享 View 模型(仅限)

转载 作者:行者123 更新时间:2023-12-04 23:44:03 25 4
gpt4 key购买 nike

我想在许多可组合项之间共享一个 View 模型。就像我们如何在 Activity 中的 fragment 之间共享 View 模型一样。
但是当我尝试这个

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 invocations can only happen from the context of a @Composable function


需要
  • View 模型应该只在 NavGraph Scope 中处于 Activity 状态。
  • 当我去不同的路线然后回来时,我应该初始化一个新的 View 模型(这就是我在 NavGraph 中调用它的原因)

  • 几乎相似的解决方案
  • Philip Dukhov 回答问题 How to share a viewmodel between two or more Jetpack composables inside a Compose NavGraph?
    但是在这种方法中, View 模型保持在启动它的 Activity 范围内,因此永远不会被垃圾收集。
  • 最佳答案

    解决方案 1
    (复制自 docs )

    The Navigation back stack stores a NavBackStackEntry not only for each individual destination, but also for each parent navigation graph that contains the individual destination. This allows you to retrieve a NavBackStackEntry that is scoped to a navigation graph. A navigation graph-scoped NavBackStackEntry provides a way to create a ViewModel that's scoped to a navigation graph, enabling you to share UI-related data between the graph's destinations. Any ViewModel objects created in this way live until the associated NavHost and its ViewModelStore are cleared or until the navigation graph is popped from the back stack.


    这意味着我们可以使用 NavBackStackEntry 来获取我们所在的导航图的范围,并将其用作 ViewModelStoreOwner获取该范围的 View 模型。
    在每个可组合项中添加它以获得 BackStackEntry对于 login然后将其用作 ViewModelStoreOwner获取 View 模型。
    val loginBackStackEntry = remember { navController.getBackStackEntry("login") }
    val loginViewModel: LoginViewModel = viewModel(loginBackStackEntry)
    所以最终代码更改为
    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

    Copied from ianhanniballake answer


    这也可以使用 extension 来实现。
  • 获取当前范围并为该范围获取或创建 View 模型

  • @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()
    }
  • 然后只需在导航图中使用此扩展程序

  • navigate(secondNestedRoute, startDestination = nestedStartRoute) {
    composable(route) {
    val loginViewModel: LoginViewModel = it.parentViewModel(navController)
    }
    }

    关于android - 如何在 NavGraph 组件之间共享 View 模型(仅限),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69642441/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com