如何为父Fragment与子Fragment提供同一ViewModel实例?
这个问题的核心在于让两个Fragment共用同一个ViewModelStoreOwner——也就是让ChildFragment使用ParentFragment的ViewModel存储,而不是自己的。你之前直接替换参数为ParentFragment报错,是因为Dagger的依赖图里没有ChildFragment到ParentFragment的实例提供关系,我们需要先补上这个链路。
步骤1:在ChildFragmentModule中提供ParentFragment实例
首先,我们需要让Dagger能从ChildFragment获取到它的ParentFragment实例,添加一个Provider方法:
@Provides fun provideParentFragment(fragment: ChildFragment): ParentFragment { // 确保ChildFragment的父Fragment确实是ParentFragment类型,避免空指针或类型错误 return requireParentFragment() as ParentFragment }
这里用requireParentFragment()替代parentFragment,可以在父Fragment不存在时直接抛出异常,方便你提前排查问题。
步骤2:修改ChildFragment的ViewModel Provider方法
接下来把ChildFragmentModule里的ViewModel提供方法,改成依赖ParentFragment而非ChildFragment:
@Provides fun provideViewModel(parentFragment: ParentFragment, myViewModelFactory: MyViewModelFactory): MyViewModel { return ViewModelProviders.of(parentFragment, myViewModelFactory).get(MyViewModelImpl::class.java) }
这样一来,ChildFragment注入的ViewModel就会从ParentFragment的ViewModelStore中获取,和ParentFragment拿到的是同一个实例,自然实现了数据共享。
为什么之前直接替换会报错?
Dagger的依赖注入是基于依赖图的,当你直接把参数换成ParentFragment时,Dagger不知道从哪里获取这个实例——因为ChildFragment的Component默认只提供ChildFragment自己的实例,没有ParentFragment的提供逻辑。补上第一步的Provider方法后,Dagger就知道如何从ChildFragment关联到ParentFragment,依赖链就通了。
额外注意事项
- 确保ChildFragment确实是作为ParentFragment的子Fragment添加的,否则
requireParentFragment()会抛出异常。 - 如果你的项目已经升级到AndroidX的
ViewModelProvider(而非旧的ViewModelProviders),代码可以改成:
@Provides fun provideViewModel(parentFragment: ParentFragment, myViewModelFactory: MyViewModelFactory): MyViewModel { return ViewModelProvider(parentFragment, myViewModelFactory)[MyViewModelImpl::class.java] }
内容的提问来源于stack exchange,提问作者mhtmalpani

