Dagger 2 错误:依赖“不能在没有 @Inject 构造函数的情况下提供”,而它实际上是用 @Inject 注释的

Posted

技术标签:

【中文标题】Dagger 2 错误:依赖“不能在没有 @Inject 构造函数的情况下提供”,而它实际上是用 @Inject 注释的【英文标题】:Dagger 2 error: dependency "cannot be provided without an @Inject constructor" while it actually annotated with @Inject 【发布时间】:2015-07-27 09:53:00 【问题描述】:

我已经开始使用 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 构造函数,但它存在!如果我将隐式 NavigationListControllerImpl 实例创建(通过@Provides-method 参数传递)替换为显式(使用new),dagger 开始抱怨相同的错误,但现在是相同模块中的第二个条目的演示者对象,并且以此类推。

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

提前谢谢你!

【问题讨论】:

如果还没有解决,能否确认@Inject注解是javax.inject.Inject? 这个问题仍然困扰着我。是的,我确认@Inject 实际上是 javax.inject.Inject。全局组件工作正常,直到我添加子组件 - 然后我得到错误。 我已经在 Dagger 2 github 页面上发布了问题。它包括更多细节github.com/google/dagger/issues/188 【参考方案1】:

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

【讨论】:

能否请您指出与此相关的文档摘录?问题是这样的修复会破坏拥有子组件的任何点 - 任何依赖项都将在全局范围内可用,并且可能意外地依赖于短期屏幕上的某些本地事物。 我添加了一个编辑,以表明我宁愿在这里使用组件依赖项。关于子组件及其模块的声明,文档并没有说清楚,但这就是我对组件和子组件的大腿耦合的理解。 感谢您在示例代码中提供的提示。关键问题是我在父组件和子@Subcomponent 中都使用了相同的@Singleton 范围。 你是对的!我编辑了我的答案以反映您的解决方案,以便其他可能阅读它的人更清楚。 这是错误的。你说对了,但你做错了; “GlobalComponent 和子组件 NavigationDrawerComponent 必须具有不同的作用域” - 如果您在两个不同作用域的组件中使用两次相同的模块(如代码示例中),dagger 编译器将抛出错误【参考方案2】:

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

我想说这是 Dagger 2 中的一个小但非常烦人的缺陷。如果子组件使用父组件扩展为依赖。但是如果父组件和子子组件共享相同的范围,编译器会报告完全误导性的错误。

感谢@lukas,在https://***.com/a/30383088/808313 给我一个提示,帮助我解决了问题。

【讨论】:

如果 dagger 2.13 在使用嵌套的不同范围时存在问题。如何使用子组件。 ?? @SagarNayak 你解决了这个问题吗?【参考方案3】:

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

【讨论】:

【参考方案4】:

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

父组件示例:

@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;
    
...

【讨论】:

Dagger 烂的更多证据。【参考方案5】:

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

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

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

现在它正在工作。

【讨论】:

这终于为我工作了!如果您使用的是最新版本的 Android Studio,即 2.2.2,则需要按照 Lord Flash 的回答使用annotationProcessor 当我使用 annotationProcessor 时,我收到此错误 - 错误:(53, 30) 错误:找不到符号变量 DaggerActivityComponent 当我使用 apt 时,我收到此错误 - 无法提供@Inject 构造函数或来自请让我知道现在该做什么?【参考方案6】:

似乎这与匕首报告的许多错误相同。在我的例子中,我的目标注入期待具体的类(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);
    

【讨论】:

以上是关于Dagger 2 错误:依赖“不能在没有 @Inject 构造函数的情况下提供”,而它实际上是用 @Inject 注释的的主要内容,如果未能解决你的问题,请参考以下文章

Android 依赖注入: Dagger 2 实例解说

Dagger 2 组件链依赖

Dagger2从入门到放弃再到恍然大悟

Dagger2从入门到放弃再到恍然大悟

将依赖项注入ViewModel时的Dagger / MissingBinding

使用 Dagger 2 管理大型多库模块项目中的依赖项