【问题标题】:How to share a viewmodel between two or more Jetpack composables inside a Compose NavGraph?如何在 Compose NavGraph 中的两个或多个 Jetpack 可组合组件之间共享视图模型?
【发布时间】:2021-08-20 06:29:50
【问题描述】:

考虑这个例子。

对于身份验证,我们将使用 2 个屏幕 - 一个用于输入电话号码,另一个用于输入 OTP。

这两个屏幕都是在 Jetpack Compose 中制作的,对于 NavGraph,我们使用的是 compose 导航。

另外我必须提到,DI 正在由 Koin 处理。

val navController = rememberNavController()

NavHost(navController) {
    navigation(
        startDestination = "phone_number_screen",
        route = "auth"
    ) {
        composable(route = "phone_number_screen") {
            // Get's a new instance of AuthViewModel
            PhoneNumberScreen(viewModel = getViewModel<AuthViewModel>())
        }

        composable(route = "otp_screen") {
            // Get's a new instance of AuthViewModel
            OTPScreen(viewModel = getViewModel<AuthViewModel>())
        }
    }
}

那么我们如何才能在 Jetpack 组合 NavGraph 中的两个或多个可组合项之间共享相同的视图模型?

【问题讨论】:

    标签: android-jetpack-compose koin jetpack-compose-navigation


    【解决方案1】:

    您可以将您的顶级viewModelStoreOwner 传递到每个目的地

    1. 直接传递给.viewModel()调用,在我的例子中是composable("first")
    2. 覆盖整个内容的LocalViewModelStoreOwner,因此CompositionLocalProvider 中的每个可组合都可以访问相同的视图模型,在我的示例中为composable("second")
    val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    }
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "first") {
        composable("first") {
            val model = viewModel<SharedModel>(viewModelStoreOwner = viewModelStoreOwner)
        }
        composable("second") {
            CompositionLocalProvider(
                LocalViewModelStoreOwner provides viewModelStoreOwner
            ) {
                SecondScreen()
            }
        }
    }
    

    在第二种情况下,您可以在组合树的任何级别获取您的模型,即CompositionLocalProvider

    @Composable
    fun SecondScreen() {
        val model = viewModel<SharedModel>()
        SomeView()
    }
    
    @Composable
    fun SomeView() {
        val model = viewModel<SharedModel>()
    }
    

    【讨论】:

    • 谢谢!这非常适合我的情况。
    【解决方案2】:

    使用 Hilt,您可以执行以下操作。但是因为你用的是 Koin 我还不知道 Koin 的方式。

    @Composable
    fun MyApp() {
        NavHost(navController, startDestination = startRoute) {
            navigation(startDestination = innerStartRoute, route = "Parent") {
                // ...
                composable("exampleWithRoute") { backStackEntry ->
                    val parentEntry = remember {
                      navController.getBackStackEntry("Parent")
                    }
                    val parentViewModel = hiltViewModel<ParentViewModel>(
                      parentEntry
                    )
                    ExampleWithRouteScreen(parentViewModel)
                }
            }
        }
    }
    

    官方文档:https://developer.android.com/jetpack/compose/libraries#hilt

    【讨论】:

    • 这是谷歌推荐的方法,效果很好。只需考虑这一点,“以这种方式创建的任何 ViewModel 对象都会一直存在,直到关联的 NavHost 及其 ViewModelStore 被清除或导航图从返回堆栈中弹出为止。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    相关资源
    最近更新 更多