【问题标题】:Shared ViewModel in scope of parent fragment using Navigation Component使用导航组件在父片段范围内共享 ViewModel
【发布时间】:2020-02-22 20:30:39
【问题描述】:

我正在尝试使用导航组件在父片段及其子片段中使用相同的 ViewModel 实例。层次结构如下: 具有navigationHost 的单个Activity。该主机有 3 个子片段,A、B 和 C。最后一个片段还有带有 2 个片段的 navigationHost: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!! })

也没有运气。

这可能还是导航库中的错误?

【问题讨论】:

    标签: android android-fragments viewmodel android-jetpack android-jetpack-navigation


    【解决方案1】:

    NavHostFragment 本身就是一个片段,所以你的结构实际上是

    Fragment C -> NavHostFragment -> Fragment X
                                  -> Fragment Y
    

    即,您从 Fragment X 获得的parentFragment 不是不是 Fragment C - 它是您在两者之间添加的NavHostFragment

    因此,如果您想从 Fragment C 获取 ViewModel,则需要使用 requireParentFragment().requireParentFragment() - NavHostFragment 的父级是 Fragment C。

    【讨论】:

    • 这行得通,谢谢?。我使用了 koin sharedViewModel(from = { requireParentFragment().requireParentFragment() }) 使用 getViewModelStoreOwner 时可以实现该结果吗?据我了解,在嵌套导航图的范围内创建 ViewModel 将为我提供 navHost 的范围,该范围与 FragmentC 不同。
    【解决方案2】:

    找不到具有此名称的参数:来自 ------------更新----

    对于那些面临同样问题的人,请查看here koin 问题讨论,也许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++
        }
    }
    

    目前,我在更改片段时运行这个,到目前为止我没有发现任何问题,如果有什么问题,我会在这里更新

    • koin_version = "2.2.1"
    • navigation_version = "2.3.5"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-01
      • 1970-01-01
      相关资源
      最近更新 更多