架构组件ViewModels使用来自Activity / Fragment的params注入匕首

时间:2017-09-08 14:59:39

标签: android mvvm dagger-2 dagger android-architecture-components

我正在尝试将新的Architecture Components ViewModel添加到我的应用程序中,同时使用dagger注入它们。我的代码基于谷歌展示的here。我试图避免为每个ViewModelFactory类型设置ViewModel,因此我使用了收到ViewModelFactory的{​​{1}}。它适用于与Map<Class<? extends ViewModel>, Provider<ViewModel>> creators范围具有依赖关系的ViewModels。但是,我的@Singleton之一具有来自片段的依赖关系。这是该片段的模块:

ViewModels

我的@Module public abstract class DownloadIssueDialogFragmentModule { @Binds abstract DialogFragment dialogFragment(DownloadIssueDialogFragment dialogFragment); @Provides @FragmentScope static Issue provideIssue(DownloadIssueDialogFragment dialogFragment) { return dialogFragment.getIssue(); } }

ViewModelModule

dagger说它无法提供@Module public abstract class ViewModelModule { @Binds abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory); @Binds @IntoMap @ViewModelKey(DownloadIssueViewModel.class) abstract ViewModel bindDownloadIssueViewModel(DownloadIssueViewModel viewModel); } 。这是有道理的,因为Issue似乎是在编译时创建的。但我只会知道该片段范围内的参数。我怎样才能做到这一点?

谢谢。

修改

最后我采用了不同的方法。现在我为每个ViewModel创建一个工厂,而不是注入ViewModel,我注入工厂。

我创建了这个库:AutoViewModelFactory

自动生成工厂。这是迄今为止我发现的最佳解决方案。

1 个答案:

答案 0 :(得分:2)

由于Android架构组件ViewModel具有比Fragments更大的范围(读取更多持久生命周期),因此应避免使ViewModel依赖于Fragment中的字段。

但是,如果Issue仅在运行时已知并且由片段中的逻辑生成,则可以通过使用Holder模式来逃避小的依赖循环问题。

这已在some other Dagger 2 StackOverflow questions中讨论过,但您只需定义一个带有公共访问者/ mutator的Java bean:

class IssueHolder {
    private Issue issue;

    @Inject
    IssueHolder() {} //empty explicit constructor as required by Dagger 2         

    public void setIssue(@Nullable Issue issue) { 
        this.issue = issue;
    }

    @Nullable
    public Issue getIssue() {
        return issue;
    }
}

然后,您可以让ViewHolder依赖于IssueHolder,而不是直接依赖Issue

@Inject IssueHolder issueHolder;

public void doSomething() {
    if (issueHolder.get() == null) {
        throw new IllegalStateException("Expected IssueHolder to be set by IssueFragment at this point");
    }
    //TODO: the logic you want here
}

与任何图案一样,这种Holder图案应该谨慎使用,因为它很容易退化。如果可能,最好的解决方案是以这种方式设计模块和依赖项,以消除循环的可能性,