【问题标题】:How to give same instance of ViewModel to both the Parent and Child fragment如何为父片段和子片段提供相同的 ViewModel 实例
【发布时间】:2018-11-05 11:57:15
【问题描述】:

有两个片段:ParentFragment 和 ChildFragment。 ChildFragment 已添加到 ParentFragment 的视图中。

现在使用Dagger2 for Android 有ParentFragmentModule 的方法:

@Provides
fun provideViewModel(fragment: ParentFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

其中 MyViewModelFactory、MyViewModel、MyViewModelImpl 是在应用中创建的简单 ViewModel 逻辑。

而 ChildFragmentModule 有方法:

@Provides
fun provideViewModel(fragment: ChildFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

这显然是在创建两个单独的 ViewModel 实例,因为它们接收到两个不同的片段实例。

我们如何让它返回相同的实例,以便在父片段和子片段之间共享数据?

我尝试在ChildFragmentModule 中传递ParentFragment 而不是ChildFragment,但这会导致Dagger 依赖注入错误。

【问题讨论】:

标签: android mvvm dependency-injection dagger android-viewmodel


【解决方案1】:

使用Activity 范围创建您的ViewModel。那么Activity 中的所有Fragment 都将获得相同的ViewModel 实例。

查看官方ViewModelProviders 参考。您可以使用ActivityFragment 范围创建ViewModel

ViewModelProvider of (FragmentActivity activity)

创建一个 ViewModelProvider,它在给定 Activity 的作用域处于活动状态时保留 ViewModel。更详细的解释在 ViewModel 中。

ViewModelProvider of (Fragment fragment)

创建一个 ViewModelProvider,它在给定片段的范围处于活动状态时保留 ViewModel。更详细的解释在 ViewModel 中。

创建ViewModel的示例代码

来自活动:

 movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);

来自片段:

 movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);

【讨论】:

  • 谢谢。这工作顺利!仅就知识而言,Parent 和 Child 片段范围同时存在。不使用Activity如何实现同样的功能?
  • 如何分享movieListViewModel到不同的模块?有可能吗
  • 单一活动方法怎么样?将所有共享视图模型都链接到一个活动是不好的。
  • 只是为了避免 NullPointerException 的修改 movieListViewModel = ViewModelProviders.of(requireActivity()).get(MovieListViewModel.class);
  • 添加这个是否可以让一个单独的活动的视图模型将数据发送到 MainActivity 的子片段?
【解决方案2】:

使用Fragment-ktx,我们可以像In **ParentFragment**那样做

 private val viewModel: DemoViewModel by viewModels()

In ChildFragment

 private val viewModel: DemoViewModel by viewModels(
    ownerProducer = { requireParentFragment() }
)

这样做我们可以在 Parent FragmentChildFragment

中获得相同的 ViewModel 实例

app -> build.grade 中添加依赖项

implementation 'androidx.fragment:fragment-ktx:1.1.0

【讨论】:

    【解决方案3】:

    在你的app -> build.gradle中实现fragment-ktx

    implementation 'androidx.fragment:fragment-ktx:1.2.5
    

    如果您使用的是导航组件 (https://developer.android.com/guide/navigation)

    在parentFragment中,可以这样获取viewModel:

    private val viewModel by viewModels<DemoViewModel>()
    

    然后当您需要 childFragment 中的 viewModel 时,您可以通过以下方式获取它:

    private val viewModel by viewModels<DemoViewModel>({requireGrandParentFragment()})
    

    requireGrandParentFragment() 是 Fragment 的自定义扩展:

    fun Fragment.requireGrandParentFragment() = this.requireParentFragment().requireParentFragment()
    

    如果你没有使用导航组件

    你可以这样访问它:

    private val viewModel by viewModels<DemoViewModel>({requireParentFragment()})
    

    【讨论】:

      【解决方案4】:

      我在所有解决方案中都尝试过同样的问题,但在我的场景中不起作用使用 requireParentFragment() 在子片段中返回 NavHostFragment 使用其他解决方案解决它

      private val viewModel: childViewModel by viewModels(
                  ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
          )
      

      在父片段中使用这个

      private val viewModel: MyOrdersVM by viewModels()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多