Dagger 2 error: dependency "cannot be provided without an @Inject constructor" while it actually annotated with @Inject

Dagger 2 error: dependency "cannot be provided without an @Inject constructor" while it actually annotated with @Inject

我已经开始使用 Dagger 2 并遇到了一个奇怪的问题,在我看来这是一个错误。

我有 3 个模块,它们组成一个子组件,后者又 extends/pluses 更高级别的组件。

子组件非常简单:只是模块的组合和单个注入点:

@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 子集提供 presenter/controller 及其依赖项:

@Module
public class SwitcherModule {

    @Provides SwitchController provideSwitcherController(SwitchControllerImpl impl) {
        return impl;
    }

    @Provides SwitcherView provideSwitcherView(SwitcherViewImpl impl) {
        return impl;
    }

}

第三个模块 - 另一个 presenter/controller 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 构造函数,但它存在!如果我将隐式 NavigationListControllerImpl 实例创建(通过 @Provides-method 参数传递)替换为显式(使用 new),则匕首开始抱怨相同的错误,但现在是演示者对象,它是相同的模块,依此类推。

所有这些情况看起来都很奇怪,我想听听更有经验的 Dagger 2 用户(和开发人员?)的一些意见。

提前致谢!

GlobalComponent 和子组件 NavigationDrawerComponent 必须具有不同的范围。为您的 GlobalComponent 使用 @Singleton,为子组件使用另一个范围。

否则,如果您将相同的作用域应用于 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);
}

看来我已经弄清楚我的 Dagger 2 设置出了什么问题。不可能在组件和子组件中使用相同的范围。 需要 为子组件定义一个新的范围。就我而言,我最终为我的子组件创建了@Screen 范围。

我想说这是 Dagger 2 中的一个小但非常烦人的缺陷。显然,如果子组件通过父组件扩展,dagger-compiler 会报告有关父组件和子组件中相同范围的不错且可以理解的错误组件作为依赖。但是如果父组件和子子组件共享相同的范围,编译器会报告完全误导性的错误。

谢谢你,@lukas,在这里给我一个提示 导致问题得到解决。

在尝试创建子组件时遇到同样的问题,但它似乎已在 Dagger 2.0.1 中修复。

我遇到了同样的错误,因为我忘记将父组件中模块提供的对象公开给依赖它的其他组件。

父组件示例:

@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);
}

更新:

应用模块:

...
    @Provides
    @Singleton
    AppPref provideAppPref() {
        return appPref;
    }
...

今天也遇到了这个问题。对我来说,注释处理存在问题(在 Android Studio 2.2 上 gradle 2.x)。

我使用了 annotationProcessor 而不是 ~~apt~~ 我用了

annotationProcessor 'com.google.dagger:dagger-compiler:2.6'

现在可以使用了。

似乎是同一种错误匕首报告了很多错误。在我的例子中,我的目标注入期望具体 class (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);
    }
}