我正在尝试将新的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
自动生成工厂。这是迄今为止我发现的最佳解决方案。
答案 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图案应该谨慎使用,因为它很容易退化。如果可能,最好的解决方案是以这种方式设计模块和依赖项,以消除循环的可能性,