如何覆盖 Dagger 2 范围内的依赖项

How to override dependencies within Scopes in Dagger 2

如何覆盖 Dagger 2 不同范围内的依赖项?示例:

我的应用程序中有两个组件:ApplicationComponentActivityComponentApplicationComponent 是基本组件,ActivityComponent 是我要执行覆盖的作用域组件。

对于这个例子,我创建了那些模型:

public class Parrot {

    private final HelloPrinter helloPrinter;

    public Parrot(HelloPrinter helloPrinter) {
        this.helloPrinter = helloPrinter;
    }

    public void sayHello(){
        helloPrinter.print();
    }
}


public interface HelloPrinter {
    void print();
}


public class AppHelloPrinter implements HelloPrinter{

    @Override
    public void print() {
        System.out.println("Hello Application");
    }
}

public class ActivityHelloPrinter implements HelloPrinter {
    @Override
    public void print() {
        System.out.println("Hello Activity");
    }
}

代码:

ApplicationComponent applicationComponent = DaggerApplicationComponent.builder().build();
applicationComponent.provideParrot().sayHello();
activityComponent = DaggerActivityComponent.builder()
                        .applicationComponent(applicationComponent).build();
activityComponent.provideParrot().sayHello();

我想要的输出是:

Hello Application
Hello Activity

所以我制作了模块:

应用模块:

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    Parrot provideParrot();
}

@Module
public class ApplicationModule {

    @Provides
    @Singleton
    HelloPrinter providePrinter(){
        return new AppHelloPrinter();
    }

    @Provides
    Parrot provideParrot(HelloPrinter helloPrinter) {
        return new Parrot(helloPrinter);
    }

}

ActivityModule: 正在尝试覆盖 HelloPrinter

@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {

    Parrot provideParrot();

}

@Module
@PerActivity
public class ActivityModule {

    @Provides
    @PerActivity
    HelloPrinter provideHelloPrinter() {
        return new ActivityHelloPrinter();
    }     
}

但是使用这个配置输出是:

Hello Application
Hello Application

我做错了什么?谢谢

简短的回答是......你不能那样做。

使用 dagger 一切都在编译时完成。

  1. 您有一个应用程序组件,它知道如何构建 HelloPrinterParrot
    然后公开 Parrot 供所有组件使用。

  2. 你有你的 activity 组件,它也知道如何构建 HelloPrinter!

那会发生什么?

记住对象图。组件知道它们可以构建什么并依赖于其他组件,从而公开已知对象。

applicationComponent.provideParrot().sayHello();

这个很简单。您创建了组件,您想要一只鹦鹉,它是使用已知打印机构建的。

activityComponent.provideParrot().sayHello();

这里发生的事情(基本上)是一样的。你说你想要一只鹦鹉。您的 activity 组件不知道如何制造一个,它只知道如何制造一台打印机!
等等。它依赖于一个应用程序组件,方便地公开一个Parrot工厂。

调用应用程序组件工厂并实例化鹦鹉。由于应用程序模块 知道 如何构建打印机,因此它使用手边的打印机。

...现在怎么样

所以...您可以在 activity 组件中提供 Parrots,然后它们将使用不同的打印机!

Gradle: error: Parrot is bound multiple times

这里我们将 2 只鹦鹉放入我们的对象图中,因为没有 "overwriting" 发生。这行不通,也不应该。

结论

无法覆盖 方法。一旦你声明第二个 ParrotHelloPrinter 它将编译失败。

实现类似功能的唯一可能性是在要使用的打印机上使用 @Named() 注释和/或将整个鹦鹉创建拉入 activity 模块。

如果我遗漏了什么请纠正我,但我什至没有看到使用命名注释保持签名相同的方法。