将Activity的ViewModel注入到Fragment的ViewModel中

4
我已经设置了一个与GithubBrowserSample非常相似的项目,因此dagger的设置是相同的。
考虑到有ActivityViewModelFragmentViewModel,它们具有非零参数构造函数,因此它们通过自定义ViewModelProvider.FactoryViewModelProviders获取。
我想要的是指示dagger在以下代码中注入已创建的ActivityViewModel实例:

    class FragmentViewModel @Inject constructor(
        private val activityViewModel: ActivityViewModel
        private val foo: Foo
    ) : ViewModel() {
        ...
    }

根据当前声明,Dagger将创建ActivityViewModel实例,而不管是否已存在该实例。
这是因为ActivityViewModel存在一个带有@Inject注释的构造函数。
因此,dagger可以自由地假定这是向FragmentViewModel提供ActivityViewModel实例的正确方式。
我知道如何为普通的Dagger创建东西,但我不知道如何为Dagger-Android做到这一点,而这个问题是特别针对Dagger-Android设置的。
作为一个临时的解决方案,我目前正在手动设置该实例:

    class MyFragment : Fragment {
      ...
      override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this, viewModelFactory).get(FragmentViewModel::class.java)
        viewModel.activityViewModel = ViewModelProviders.of(activity!!, viewModelFactory).get(ActivityViewModel::class.java)
      }
      ...
    }

正确的方式是将父ViewModel注入到子ViewModel中吗?

1
你为什么想要在一个ViewModel中使用另一个ViewModel呢? - Deividas Strioga
根据其目的,它们应该帮助填充视图并响应UI事件。片段/活动应该发出命令并在之间进行通信。我认为这是更好的架构决策。 - Deividas Strioga
@DeividasStrioga,假设您的活动中有一个当前隐藏的“ProgressBar”。现在,在您的片段内,您正在发出一个操作,应该启动显示“ProgressBar”。您将如何建立此通信? - azizbekian
1
@DeividasStrioga,先生,使用DataBinding还是普通的findViewById()有什么关系呢?“我会直接从片段中进行操作,通知它的活动。”为什么片段需要了解活动的视图层次结构呢? - azizbekian
@azizbekian,您想要实现的目标可以通过正确的模块作用域来完成。您能分享一下您的片段吗? - Ayokunle Paul
显示剩余8条评论
1个回答

1
这不是对问题的答案,而是我想出并目前使用的一种方法。
已经声明了以下扩展函数:
inline fun <reified T : ViewModel> Fragment.getViewModel(
    factory: ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory()
) = ViewModelProviders.of(this, factory).get(T::class.java)

inline fun <reified T : ViewModel> Fragment.getParentViewModel(
    factory: ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory()
) = ViewModelProviders.of(activity!!, factory).get(T::class.java)

然后在片段类中,我们可以声明以下内容:
private val parentViewModel by lazy { getParentViewModel<ParentViewModel>(viewModelFactory) }
private val childViewModel by lazy {
  val field = getViewModel<ChildViewModel>(viewModelFactory)
  field.parentViewModel = parentViewModel
  field
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接