前言
之前遇到了需要在某一个Page中的某个可组合项里使用navHostController的情况。想到的方法是从Nav传参,一直传到目标可组合项,或者提供一个 onNavigateToXXXScreenClick: () -> Unit 一直传到Nav里,在里面放跳转代码。
但是这些方法都太麻烦了,在查看了 Loliball 的 Kikoeru 项目中的相关实现后,学习到了CompositionLocalProvider方法,它可以像View架构的全局变量一样,让它的作用域内都可以访问这个全局变量,非常方便。
使用方法
val LocalRootNav = staticCompositionLocalOf<NavHostController> {
error("LocalRootNav Not Provide")
}
val navController = rememberNavController()
CompositionLocalProvider(
LocalRootNav provides navController
) {
RootNavHost(navController)
}
LocalRootNav 是一个 staticCompositionLocalOf<NavHostController>,它创建了一个可以在 Compose 层级树中传播的本地值。
CompositionLocalProvider 是一个作用域提供器,它会将一个本地值传递给其子树中的所有可组合项。
这样,在 CompositionLocalProvider 的作用范围内,RootNavHost内的所有子可组合项都可以访问这个变量了!
下面是使用示例
// 在 RootNavHost 内部,可以通过 LocalRootNav 获取 navController
val navController = LocalRootNav.current
在有多个Page需要使用同一个ViewModel的时候,经过考虑,我使用了这个方法提供全局ViewModel实例。经过测试,hiltViewModel(), viewModel() 和 Activity中的 by viewModels() 提供的都是不同的viewModel实例,它们生命周期的差异让viewModel的管理变得较为困难。若有其他好方法可以在评论区发表见解。请大家多指教!