Dagger 2问题覆盖单一提供了应用程序使用的库中的模块的注释方法

qaz*_*sab 14 java android dependency-injection dagger dagger-2

GitHub项目链接

在GitHub上做了一个项目,它是我项目实际架构的匕首2架构的模型.这个问题将基于GitHub项目.

我在这个问题中提供了很多代码片段,但是,在Android Studio中自己编译项目以理解问题可能更容易.

如果你检查代码,它将无法编译.进入AppModule.java并注释掉两个提供方法,它应该编译.

主要问题是这篇文章的最后一行.

https://github.com/qazimusab/Dagger2LibraryProject

建筑

我有一个库,其中包含制作应用程序所需的所有代码.这个架构的重点是我在项目中创建的每个应用程序都应该能够使用库,并且通过dagger 2,能够为它自己的模块中的任何单个类或活动提供不同的实现.此时,我在此示例项目中只有一个使用该库的应用程序.

问题

使用dagger,我有相同的体系结构,在app特定的模块(而不是库模块)中,我能够添加一个新的提供注释方法来覆盖任何库模块中提供的任何实现只要

  1. 该方法位于app模块的模块中
  2. 该方法使用@Provides注释
  3. 该方法具有与要覆盖的方法相同的返回类型

使用Dagger 2时,架构可以在我不覆盖任何提供时工作,或者如果我这样做,当我覆盖该模块中的每个提供并从特定于应用程序模块的包中删除该模块时.

例如,在我的项目中,我有一个应用程序和一个库.

该应用程序有一个AppModule; 图书馆有一个CatModule提供Cat和CatFood,一个狗模块提供Dog and DogFood,以及一个LibraryModule提供活动.

CatModule.java

package com.example.qaziahmed.library.application.modules;

import com.example.qaziahmed.library.classes.Cat; import
com.example.qaziahmed.library.classes.CatFood; import
com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.ICatFood;

import javax.inject.Singleton;

import dagger.Module; import dagger.Provides;

/**  * Created by qaziahmed on 11/23/15.  */ @Module public class
CatModule {

    @Provides
    @Singleton
    ICat provideCat() {
        return new Cat();
    }

    @Provides
    ICatFood provideCatFood(){
        return new CatFood();
    } }
Run Code Online (Sandbox Code Playgroud)

DogModule.java

package com.example.qaziahmed.library.application.modules;

import com.example.qaziahmed.library.classes.Dog; import
com.example.qaziahmed.library.classes.DogFood; import
com.example.qaziahmed.library.classes.contract.IDog; import
com.example.qaziahmed.library.classes.contract.IDogFood;

import javax.inject.Singleton;

import dagger.Module; import dagger.Provides;

/**  * Created by qaziahmed on 11/23/15.  */ @Module public class
DogModule {

    @Provides
    @Singleton
    IDog provideDog() {
        return new Dog();
    }

    @Provides
    IDogFood provideDogFood(){
        return new DogFood();
    }

}
Run Code Online (Sandbox Code Playgroud)

所以,我的应用程序模块中,我想提供一个家猫实施的ICAT,而不是一般的猫IDogFood,而不是只是普通的狗食的AllNaturalDogFood执行,然后在我的AppModule我添加两个提供覆盖那些

AppModule.java

package com.example.qaziahmed.dagger2libraryproject.application;

import
com.example.qaziahmed.dagger2libraryproject.classes.AllNaturalDogFood;
import com.example.qaziahmed.dagger2libraryproject.classes.HouseCat;
import com.example.qaziahmed.library.application.modules.CatModule;
import com.example.qaziahmed.library.application.modules.DogModule;
import
com.example.qaziahmed.library.application.modules.LibraryModule;
import com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.IDogFood;

import javax.inject.Singleton;

import dagger.Module; import dagger.Provides;

/**  * Created by ogre on 2015-07-12  */ @Module(includes = {
        LibraryModule.class,
        DogModule.class,
        CatModule.class }) public class AppModule {

    @Provides
    @Singleton
    ICat provideHouseCat() {
        return new HouseCat();
    }

    @Provides
    IDogFood provideAllNaturalDogFood(){
        return new AllNaturalDogFood();
    } }
Run Code Online (Sandbox Code Playgroud)

现在,当我运行此设置时,这是我得到的错误:

错误:com.example.qaziahmed.library.classes.contract.ICat势必多次:@Provides @Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideHouseCat ()@Provides @Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.library.application.modules.CatModule.provideCat()错误:com.example.qaziahmed.library.classes.contract. IDogFood势必多次:@Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideAllNaturalDogFood()@Provides com.example.qaziahmed.library.classes.contract. IDogFood com.example.qaziahmed.library.application.modules.DogModule.provideDogFood()

现在,如果在AppModule.java中,我还添加了提供注释的方法来提供Cat Food和Provide Dog,然后从App Module中的includes中删除CatModule.class和DogModule.class然后它就可以了.

但是,整个问题是我如何覆盖库中某个模块中的单个提供方法,而不必覆盖该特定模块中的每个提供带注释的方法,然后从AppModule.java中的包中删除该模块

Ogn*_*yan 10

将尝试从Dagger 2文档中解密此引用:

Dagger 2不支持覆盖.覆盖简单测试假货的模块可以创建模块的子类来模拟该行为.应该分解使用覆盖并依赖依赖注入的模块,以便将被覆盖的模块表示为两个模块之间的选择.

在当前示例中,您不依赖于依赖项注入,因为您的provides*方法创建了简单的新对象,因此您只需创建模块的子类,覆盖provides需要重写的方法,然后在组件中包含该新模块.

如果您依赖DI(实际上您将在项目的某个阶段)依赖于此:

@Provides
@Singleton
ICat provideCat(IBowtie bowtie) { // 'bowtie' needs to be injected
    return new CatWithBowtie(Bowtie);
}
Run Code Online (Sandbox Code Playgroud)

它涉及"使用覆盖并依赖依赖注入的模块应该被分解",这基本上意味着:你必须分成CatModule两部分:CatModule只使用providesCat'和'CatFoodModule' provideCatFood().然后你的应用程序的组件,你只需使用新的CatWithBowtieModule而不是CatModule.

有两个有用的建议:

  1. 在库项目中拆分模块,因此provides*每个模块只有一个方法.是的,它听起来像BS,但这是在您的应用程序中稍后提供轻松覆盖的唯一方法.

  2. 暂时让我们假装图书馆是作为JAR/AAP从第三方提供给你的,你甚至没有资源.在这种情况下,您将无法重用lib中定义的模块,因此您必须自己创建所有模块.这正是Dagger 2所发生的事情.

当您尝试直接在应用程序中使用lib中的模块时(就像您一样),这两个项目不再是两个独立的项目,而是一个看起来像两个项目的项目(clusterf*ck紧密耦合).应用程序依赖于lib是可以的,但是lib依赖于应用程序是不行的.它归结为:在Dagger 2中,最好不要使用交叉(项目)边界modulescomponents.

有人可能会问:"如果我不能在我的应用程序中使用lib's modules/ 那么在lib中使用Dagger 2会有什么好处components?!".那么,你仍然可以在你的单元测试中使用你的匕首modules/ components毕竟这是使用Dagger的主要好处.此外,如果您的lib可能被其他人使用,您可以(必须?)提供一个参考应用程序,该应用程序显示如何"连接"事物,以便lib的用户能够只是复制该代码(如果它适合他们)或至少看看如何开始.


JFP*_*ard 8

问题是您的Injection看到两个提供相同对象的方法.

如果您阅读此链接:http://google.github.io/dagger/您可以通过将您的提供商命名为:

@Provides @Named("water")
Run Code Online (Sandbox Code Playgroud)

然后,在您的注射中,引用它像:

@Inject @Named("water")
Run Code Online (Sandbox Code Playgroud)