如何在Dagger 2中覆盖Scopes中的依赖项

Add*_*dev 6 java android dependency-injection dagger dagger-2

如何在Dagger 2的不同范围内覆盖依赖关系?例:

我的应用程序中有两个组件:ApplicationComponentActivityComponent.ApplicationComponent是基本组件,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");
    }
}
Run Code Online (Sandbox Code Playgroud)

和代码:

ApplicationComponent applicationComponent = DaggerApplicationComponent.builder().build();
applicationComponent.provideParrot().sayHello();
activityComponent = DaggerActivityComponent.builder()
                        .applicationComponent(applicationComponent).build();
activityComponent.provideParrot().sayHello();
Run Code Online (Sandbox Code Playgroud)

我想要的输出是:

Hello Application
Hello Activity
Run Code Online (Sandbox Code Playgroud)

所以我制作了模块:

ApplicationModule:

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

}
Run Code Online (Sandbox Code Playgroud)

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();
    }     
}
Run Code Online (Sandbox Code Playgroud)

但是使用此配置,输出为:

Hello Application
Hello Application
Run Code Online (Sandbox Code Playgroud)

我做错了什么?谢谢

Dav*_*jak 6

简短的答案是...您无法做到。

使用匕首,一切都在编译时完成。

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

  2. 您拥有活动组件,该组件也知道如何构造HelloPrinter

那会怎样呢?

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

applicationComponent.provideParrot().sayHello();
Run Code Online (Sandbox Code Playgroud)

这很容易。您创建组件,想要一个鹦鹉,它是使用已知的打印机构造的。

activityComponent.provideParrot().sayHello();
Run Code Online (Sandbox Code Playgroud)

这里发生的(基本上)是相同的。你说你想要一只鹦鹉。您的活动组件不知道如何制造打印机,只知道如何制造打印机!
可是等等。它依赖于应用程序组件,可以方便地公开ParrotFactory。

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

...怎么办

所以...您可以在活动组件中提供鹦鹉,然后他们将使用其他打印机!

Gradle:错误:鹦鹉被绑定多次

在这里,由于没有“覆盖”发生,因此我们将2个鹦鹉放入对象图。这行不通,也不应该。

结论

没有方法可以覆盖方法。一旦声明一秒钟,Parrot否则HelloPrinter编译将失败。

要实现类似功能,唯一的可能性是在要使用的@Named()打印机上使用注释,并且/或者将整个鹦鹉创建工作放到活动模块中。

并且,如果我缺少某些内容,请更正我,但我什至看不到使用命名注释使签名保持相同的方法。