使用导航组件在父片段范围内共享 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"