Java Dagger2问题覆盖单提供了应用程序使用的库中模块的带注释方法

Java Dagger2问题覆盖单提供了应用程序使用的库中模块的带注释方法,java,android,dependency-injection,dagger,dagger-2,Java,Android,Dependency Injection,Dagger,Dagger 2,GitHub项目链接 我制作了一个模型,它是我的项目实际架构的匕首2架构的模型。这个问题将基于GitHub项目 在这个问题上,我已经提供了很多代码片段,但是,在androidstudio中自己编译项目可能更容易理解这个问题 如果您签出代码,它将无法编译。进入AppModule.java并注释掉这两个提供的方法,它应该编译 主要问题是这篇文章的最后一行 架构 我有一个库,其中包含制作应用程序所需的所有代码。这种架构的要点是,我在项目中创建的每个应用程序都应该能够使用库,并且通过dagger 2,

GitHub项目链接

我制作了一个模型,它是我的项目实际架构的匕首2架构的模型。这个问题将基于GitHub项目

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

如果您签出代码,它将无法编译。进入AppModule.java并注释掉这两个提供的方法,它应该编译

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

架构

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

问题

使用dagger one,我拥有相同的体系结构,在特定于应用程序的模块(与库模块相反)中,我能够添加一个新的提供注释的方法来覆盖任何库模块中提供的任何实现,只要

  • 该方法位于应用程序模块中的模块中
  • 该方法用@Provides注释
  • 该方法的返回类型与要重写的返回类型相同
  • 对于Dagger 2,当我不重写任何提供时,或者如果我重写了,当我重写该模块中的每个提供并从特定于应用程序的模块的包含中删除该模块时,体系结构就会工作

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

    该应用程序有一个AppModule;图书馆有一个提供猫和猫食的CatModule,一个提供狗和狗食的dog module,以及一个提供活动的library module

    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();
        } }
    
    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();
        }
    
    }
    
    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();
        } }
    
    DogModule.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();
        } }
    
    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();
        }
    
    }
    
    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();
        } }
    
    因此,在我的应用程序模块中,我想提供一个ICat的house cat实现,而不是通用的cat,以及一个IDogFood的AllNaturalDogFood实现,而不仅仅是普通的DogFood,然后在我的AppModule中添加两个提供来覆盖这些

    AppModule.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();
        } }
    
    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();
        }
    
    }
    
    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();
        } }
    
    现在,当我运行此安装程序时,我得到的错误是:

    错误:com.example.qaziahmed.library.classes.contract.ICat被绑定多次: @提供@Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideHouseCat() @提供@Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.library.application.modules.CatModule.provideCat() 错误:com.example.qaziahmed.library.classes.contract.IDogFood被绑定多次: @提供com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.dagger2libraryproject.application.AppModule.providelnaturaldogfood() @提供com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.library.application.modules.dogmule.provideDogFood()

    现在,如果在AppModule.java中,我还添加了提供带注释的方法来提供猫食和狗食,然后从includes in-App模块中删除CatModule.class和DogModule.class,那么它就可以工作了


    但是,整个问题是如何重写库中某个模块中的单个提供方法,而不必重写该特定模块中的每个提供注释的方法,然后将该模块从AppModule.java的includes中删除。问题是,您的注入看到两个提供相同功能的方法反对

    如果您阅读此链接:您可以将您的提供商命名为:

    @Provides @Named("water")
    
    然后,在您的注射中,引用如下内容:

    @Inject @Named("water")
    

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

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

    在当前示例中,您不依赖依赖依赖项注入,因为
    提供*
    方法创建简单的新对象,这样您就可以只创建模块的子类,重写需要重写的
    提供
    方法,然后将新模块包含在组件中

    当您依赖DI时(实际上,您将在项目的某个阶段使用DI),如下所示:

    @Provides
    @Singleton
    ICat provideCat(IBowtie bowtie) { // 'bowtie' needs to be injected
        return new CatWithBowtie(Bowtie);
    }
    
    它涉及到“应该分解使用覆盖和依赖依赖依赖注入的模块”,这基本上意味着:您必须将
    CatModule
    分为两部分:
    CatModule
    ,只使用
    providecat
    provideCatFood()的“CatFoodModule”。然后,您的应用程序组件只需使用新的
    CatWithBowtieModule
    而不是
    CatModule

    有两个有用的建议:

  • 在库项目中分割模块,因此每个模块只有一个
    提供*
    方法。是的,这听起来像BS,但这是在应用程序中提供轻松覆盖的唯一方法

  • 暂时让我们假设这个库是作为JAR/AAP从第三方提供给您的,而您甚至没有源代码。在这种情况下,您将无法重用库中定义的模块,因此您必须自己创建所有模块。匕首2就是这样

  • 当你尝试直接在应用程序中使用lib中的模块时(正如你所做的那样),这两个项目不再是两个独立的项目,而是一个看起来像两个项目(clusterf*ck)的项目