Dagger 2 问题覆盖单个提供了来自应用使用的库中的模块的带注释的方法

GitHub 项目链接

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

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

如果签出代码,它将不会编译。进入AppModule.java并注释掉两者都提供了方法,它应该编译。

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

https://github.com/qazimusab/Dagger2LibraryProject

建筑

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

问题

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

  1. 该方法位于应用模块的模块中
  2. 该方法用@Provides
  3. 该方法的返回类型与要重写的方法具有相同的返回类型

使用 Dagger 2,当我不覆盖任何提供时,或者如果我覆盖了该模块中的每个提供,并从应用程序特定模块的包含中删除该模块,则体系结构可以正常工作。

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

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

猫咪.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();
    } }

狗模块.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();
    }

}

因此,在我的应用程序模块中,我想提供ICat的家猫实现而不是通用猫和IDogFood的AllNaturalDogFood实现,而不仅仅是常规的DogFood,然后在我的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();
    } }

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

Error: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() Error:com.example.qaziahmed.library.classes.contract.IDogFood 被绑定多个times: @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 中的包含中删除 CatModule.class 和 DogModule.class然后它就可以工作了。

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


答案 1

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

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

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

当你依赖DI时(实际上你会在项目的某个阶段),就像这样:

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

它涉及到“使用覆盖并依赖注入的模块应该被分解”,这基本上意味着:你必须分成两部分:just和'CatFoodModule'与。然后,您的应用程序组件您只需使用新的而不是.CatModuleCatModuleprovidesCatprovideCatFood()CatWithBowtieModuleCatModule

有两个有用的建议:

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

  2. 让我们假装该库是从第三方作为JAR / AAP提供给您的,并且您甚至没有源代码。在这种情况下,您将无法重用库中定义的模块,因此您必须自己创建所有这些模块。这正是《匕首2》所发生的事情。

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

有人可能会问:“如果我不能在我的应用程序中使用lib的,那么在lib中使用Dagger 2有什么好处?!好吧,您仍然可以在单元测试中使用匕首/,这毕竟是使用匕首的主要好处。此外,如果你的lib打算被其他人使用,你可以(必须?)提供一个参考应用程序,显示如何“连接”东西,这样lib的用户将能够复制该代码,如果它适合他们,或者至少看看如何开始。modulescomponentsmodulescomponents


答案 2

问题是您的注入看到两个提供相同对象的方法。

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

@Provides @Named("water")

然后,在您的注射中,引用它,如下所示:

@Inject @Named("water")

推荐