47

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

我有 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如果我用显式(with )替换隐式 NavigationListControllerImpl 实例创建(通过-method 参数传递new),dagger 开始抱怨相同的错误,但现在是相同模块中的第二个条目的演示者对象,依此类推。

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

先感谢您!

4

6 回答 6

57

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

父组件示例:

@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;
    }
...
于 2016-06-16T00:04:50.447 回答
19

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);
}
于 2015-05-21T19:51:12.913 回答
17

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

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

谢谢你,@lukas,在这里给我一个提示https://stackoverflow.com/a/30383088/808313导致问题解决。

于 2015-05-22T11:59:11.603 回答
4

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

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

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

现在它正在工作。

于 2016-08-14T12:21:36.740 回答
2

似乎对于许多错误来说,这是同样的错误匕首报告。就我而言,我的目标注入期待具体的类(Presenter),因为提供 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);
    }
}
于 2017-04-13T08:16:52.083 回答
2

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

于 2015-07-10T14:31:09.033 回答