我已经开始使用Dagger 2并遇到一个奇怪的问题,看起来像是一个bug。
我有3个模块,它们组成一个子组件,后者又扩展/加载更高级别的组件。
子组件非常简单:只需组合模块和单个注入点:
@Singleton
@Subcomponent(
modules = {
NavigationDrawerModule.class,
NavigationListModule.class,
SwitcherModule.class
}
)
public interface NavigationDrawerComponent {
NavigationDrawerFragment inject(NavigationDrawerFragment object);
}
第一个模块看起来像这样 - 它提供了一般的片段级依赖关系:
@Module
public class NavigationDrawerModule {
private final Activity activity;
private final View rootView;
private final LoaderManager loaderManager;
public NavigationDrawerModule(Activity activity, View rootView, LoaderManager loaderManager) {
this.activity = activity;
this.rootView = rootView;
this.loaderManager = loaderManager;
}
@Provides @Singleton EventBus provideLocalBus() {
return EventBus.builder().build();
}
@Provides @Singleton View provideViewRoot() {
return rootView;
}
@Provides @Singleton LoaderManager provideLoaderManager() {
return loaderManager;
}
@Provides @Singleton Context provideContext() {
return activity;
}
}
第二个模块看起来像这样 - 它为屏幕上的UI子集提供演示者/控制器及其依赖关系:
@Module
public class SwitcherModule {
@Provides SwitchController provideSwitcherController(SwitchControllerImpl impl) {
return impl;
}
@Provides SwitcherView provideSwitcherView(SwitcherViewImpl impl) {
return impl;
}
}
第三个模块 - 用于UI子集的另一个演示者/控制器:
@Module
public class NavigationListModule {
@Provides @Singleton NavigationListController provideNavigationListController(NavigationListControllerImpl impl) {
return impl;
}
@Provides @Singleton NavigationListView provideNavigationListView(NavigationListViewImpl impl) {
return impl;
}
}
正在注入的片段的相关部分:
@Inject SwitchController identitySwitchController;
@Inject SwitcherView identitySwitcherView;
@Inject NavigationListController navigationListController;
@Inject NavigationListView navigationListView;
NavigationListControllerImpl
实现以下构造函数:
@Inject
public NavigationListControllerImpl(Context ctx, EventBus bus) {
this.ctx = ctx;
this.bus = bus;
}
我从Dagger 2编译器得到的错误如下:
error: ...sidenavigation.navigationlist.NavigationListControllerImpl cannot be provided without an @Inject constructor or from an @Provides-annotated method.
...sidenavigation.NavigationDrawerFragment.navigationListController
[injected field of type: ...sidenavigation.navigationlist.NavigationListController navigationListController]
...sidenavigation.navigationlist.NavigationListModule.provideNavigationListController(...sidenavigation.navigationlist.NavigationListControllerImpl impl)
[parameter: ...sidenavigation.navigationlist.NavigationListControllerImpl impl]
错误抱怨缺少@Inject-annotated构造函数,但它存在!如果我用显式(带@Provides
)替换隐式的NavigationListControllerImpl实例创建(通过new
- 方法参数传递),dagger开始抱怨相同的错误,但现在对于presenter对象,这是第二个条目相同的模块,等等。
所有这些情况看起来都很奇怪,我想听听更有经验的Dagger 2用户(以及开发人员?)的一些意见。
提前谢谢!
答案 0 :(得分:48)
我遇到了同样的错误,因为我忘了将父组件中的模块提供的对象暴露给依赖它的其他组件。
父组件示例:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
AppPref exposeAppPref(); /* my issue was caused by forgot this line,
the method name doesn't matter, what matters is the object type AppPref provided in the AppModule
that you want it to be available in the component that declares this component as one of its dependencies*/
}
将上述组件作为依赖项的示例组件
@UserScope
@Component (dependencies = {AppComponent.class})
public interface ActivityComponent {
void inject(MainActivity activity);
}
更新:
AppModule:
...
@Provides
@Singleton
AppPref provideAppPref() {
return appPref;
}
...
答案 1 :(得分:17)
GlobalComponent和子组件NavigationDrawerComponent必须具有不同的范围。将@Singleton用于GlobalComponent,并使用另一个子组件范围。
否则,如果将相同的范围应用于GlobalComponent和子组件,则还必须在全局组件中声明子组件的模块:
@Component(
// modules from subcomponent must be declared here also
modules = {NavigationListModule.class,
SwitcherModule.class,
NavigationDrawerModule.class,
...}
)
@Singleton
public interface GlobalComponent {
NavigationDrawerComponent plus(NavigationDrawerModule module);
}
对于您的用例,您还可以使用组件依赖项。例如:
@Component(
dependencies = GlobalComponent.class,
modules = {NavigationListModule.class,
SwitcherModule.class,
NavigationDrawerModule.class}
)
@YourOtherDaggerScope // @Singleton scope won't work here, it must be a different scope
public interface NavigationDrawerComponent extends GlobalComponent { // extend the parent component if you wish to get access to parent dependencies
NavigationDrawerFragment inject(NavigationDrawerFragment object);
}
答案 2 :(得分:15)
好像我已经弄清楚Dagger 2设置有什么问题了。在组件和子组件中都不可能使用相同的范围。 required 为子组件定义新范围。在我的情况下,我最终为我的子组件创建了@Screen范围。
我会说这是Dagger 2中的一个小但非常烦人的缺陷。显然,如果使用父组件扩展子组件,则dagger-compiler会报告父组件和子组件中相同范围的错误且可理解的错误依赖。但是,如果父组件和子子组件共享相同的范围,则编译器会报告完全误导性的错误。
谢谢你,@ lukas,在这里给我一个提示https://stackoverflow.com/a/30383088/808313导致问题解决。
答案 3 :(得分:4)
今天也遇到了这个问题。对我来说,注释处理存在问题(在带有gradle 2.x的Android Studio 2.2上)。
而不是~~ apt ~~我使用了annotationProcessor 我用了
annotationProcessor 'com.google.dagger:dagger-compiler:2.6'
现在它正在工作。
答案 4 :(得分:2)
在尝试创建子组件时遇到了同样的问题,但似乎在Dagger 2.0.1中修复了。
答案 5 :(得分:1)
似乎它有同样的错误匕首报告许多错误。在我的情况下,我的目标注入期望具体类(Presenter),因为提供演示者的模块只返回接口(DemoContract.Presenter)
从
改变@Inject
public Presenter mDemoPresenter;
以强>
@Inject
public DemoContract.Presenter mDemoPresenter;
和提供演示者的模块如下所示:
@Module
public class DiDemoPresenterModule {
private final DemoContract.View mView;
DiDemoPresenterModule(MainActivity mView) {
this.mView = mView;
}
@Provides
public DemoContract.Presenter providesDemoPresenter(Repository repository) {
return new DemoPresenter(repository, mView);
}
}