使用导航组件在父片段范围内共享 ViewModel
Shared ViewModel in scope of parent fragment using Navigation Component
我正在尝试使用导航组件在父片段及其子片段中使用相同的 ViewModel 实例。层次结构如下:具有 navigationHost 的单个 Activity。该主机有 3 个子片段,A、B 和 C。最后一个片段还有带有 2 个片段的导航主机:X 和 Y。下图说明了层次结构。
预计:
我想与片段 X 和 Y 共享片段 C ViewModel 的相同实例。
当前:
片段 C 的 ViewModel 被初始化两次:一次是在片段 C 初始化时,第二次是在片段 X 初始化时。片段 X 被设置为片段 C 导航图中的默认目的地。当我将默认目标更改为 Y 时,ViewModel 在 C 和 Y 中初始化。
我已经尝试过的:
在子视图模型中我使用这个:
val viewModel: ParentViewModel =
ViewModelProvider(findNavController().getViewModelStoreOwner(R.id.parent_graph)).get(
ParentViewModel::class.java
)
在父视图模型中我使用这个:
val viewModel by viewModels<ParentViewModel>()
我还尝试使用片段范围的 Koin sharedViewModel 注入 viewModel:
val viewModel by sharedViewModel<ParentViewModel>(from = { parentFragment!! })
也没有运气。
这可能是导航库中的错误吗?
一个NavHostFragment
本身就是片段,所以你的结构其实是
Fragment C -> NavHostFragment -> Fragment X
-> Fragment Y
即,您从片段 X 获得的 parentFragment
是 而不是 片段 C - 它是您在两者之间添加的 NavHostFragment
。
因此,如果您想从片段 C 中获取 ViewModel
,则需要使用 requireParentFragment().requireParentFragment()
- 您的 NavHostFragment
的父级是片段 C。
找不到具有此名称的参数:来自
----------更新----------------
对于面临同样问题的人,检查here koin issue discuss about, and maybe here可能会有帮助。
我正在使用
//child fragment
private val viewModel: TripParentViewModel by viewModel(owner = { ViewModelOwner.Companion.from(requireParentFragment().requireParentFragment().viewModelStore)})
//parent fragment
private val parentViewModel by viewModel<TripParentViewModel>()
作为解决方案,
class TripParentViewModel:ViewModel() {
var count = 0
fun test(){
when(count){
0 -> Timber.d("first click")
1 -> Timber.d("second click")
2 -> Timber.d("third click")
}
Timber.d(count.toString())
count++
}
}
目前,我运行这个when change fragment,目前没发现什么问题,如果有什么问题,我会在这里更新
- koin_version = "2.2.1"
- navigation_version = "2.3.5"
我正在尝试使用导航组件在父片段及其子片段中使用相同的 ViewModel 实例。层次结构如下:具有 navigationHost 的单个 Activity。该主机有 3 个子片段,A、B 和 C。最后一个片段还有带有 2 个片段的导航主机:X 和 Y。下图说明了层次结构。
预计: 我想与片段 X 和 Y 共享片段 C ViewModel 的相同实例。
当前: 片段 C 的 ViewModel 被初始化两次:一次是在片段 C 初始化时,第二次是在片段 X 初始化时。片段 X 被设置为片段 C 导航图中的默认目的地。当我将默认目标更改为 Y 时,ViewModel 在 C 和 Y 中初始化。
我已经尝试过的: 在子视图模型中我使用这个:
val viewModel: ParentViewModel =
ViewModelProvider(findNavController().getViewModelStoreOwner(R.id.parent_graph)).get(
ParentViewModel::class.java
)
在父视图模型中我使用这个:
val viewModel by viewModels<ParentViewModel>()
我还尝试使用片段范围的 Koin sharedViewModel 注入 viewModel:
val viewModel by sharedViewModel<ParentViewModel>(from = { parentFragment!! })
也没有运气。
这可能是导航库中的错误吗?
一个NavHostFragment
本身就是片段,所以你的结构其实是
Fragment C -> NavHostFragment -> Fragment X
-> Fragment Y
即,您从片段 X 获得的 parentFragment
是 而不是 片段 C - 它是您在两者之间添加的 NavHostFragment
。
因此,如果您想从片段 C 中获取 ViewModel
,则需要使用 requireParentFragment().requireParentFragment()
- 您的 NavHostFragment
的父级是片段 C。
找不到具有此名称的参数:来自 ----------更新----------------
对于面临同样问题的人,检查here koin issue discuss about, and maybe here可能会有帮助。
我正在使用
//child fragment
private val viewModel: TripParentViewModel by viewModel(owner = { ViewModelOwner.Companion.from(requireParentFragment().requireParentFragment().viewModelStore)})
//parent fragment
private val parentViewModel by viewModel<TripParentViewModel>()
作为解决方案,
class TripParentViewModel:ViewModel() {
var count = 0
fun test(){
when(count){
0 -> Timber.d("first click")
1 -> Timber.d("second click")
2 -> Timber.d("third click")
}
Timber.d(count.toString())
count++
}
}
目前,我运行这个when change fragment,目前没发现什么问题,如果有什么问题,我会在这里更新
- koin_version = "2.2.1"
- navigation_version = "2.3.5"