多个实例中的Dagger 2单身人士

时间:2016-09-07 17:33:06

标签: java dependency-injection inversion-of-control dagger-2

我刚刚测试了Dagger 2,我对单例注释有一些奇怪的行为。我创建了一些测试代码来显示我的问题。

我的模块:

@Module
public class App {

    @Provides
    @Singleton
    ThingA provideThingA(){
        return new ConcreteThingA();
    }

}

我想要单身的东西的接口:

public interface ThingA {
    void showMyId();
}

实现:

public class ConcreteThingA implements ThingA {
    @Override
    public void showMyId() {
        System.out.println(this);
    }
}

执行Dagger的代码:

public void doStuff() {
    ThingA thingA=DaggerThingAComponent.create().provideThingA();
    ThingA thingB=DaggerThingAComponent.create().provideThingA();
    System.out.println("Hello");
}

这是一个屏幕截图,显示当我要求它两次时,我没有得到相同的实例。我错过了什么基本的东西? ThingA只是一个愚蠢的名字,在我的实际应用中,我希望在我的服务上有这种单身行为。

Debug screenshot

1 个答案:

答案 0 :(得分:9)

诀窍是Dagger通过组件强制执行范围/生命周期,并且您在此处创建了两个单独的组件:

ThingA thingA = DaggerThingAComponent.create().provideThingA();
ThingA thingB = DaggerThingAComponent.create().provideThingA();

每次创建新的顶级@ Singleton注释组件时,Dagger都会为每个@Singleton对象创建一个带有全新容器的全新对象图。你应该改为:

ThingAComponent component = DaggerThingAComponent.create();
ThingA thingA = component.provideThingA();
ThingA thingB = component.provideThingA();  // thingA == thingB

当然,通过依赖图进一步访问的所有内容都来自同一个组件,因此这将保留您正在寻找的单例行为。

在大多数情况下,您不需要传递组件:组件应该用于顶级组件,并且通过注入器可访问的任何内容都应该@Inject其依赖项(这意味着它不应该需要参考组件本身)。在迁移到DI或Dagger期间,这可能会出现问题,但创建多个@Singleton组件并不是解决问题的方法。相反,请尝试以下方法之一:

  • 如果您需要多个实例,无论您是否创建了Provider<T>方法,都可以始终注入T而不是@Provides。就此而言,如果您只需要零个或一个特定依赖项的副本,则可以注入Lazy<T>,尤其是在创建该对象特别重的情况下。
  • 如果您需要在对象图中深入了解组件本身,则可以@Inject组件本身,尽管它只是@Inject Provider<T> tProvider而不是@Inject YourComponent只能调用YourComponent.getT
  • 在某些情况下,包括Android,将组件保存到全局可访问的字段可能是有意义的,可以是应用程序中的实例字段,也可以是其他地方的静态字段。这是因为Android反过来自己创建对象,而不是从图中获取注入的实例。对于所有其他情况,请注入依赖项以避免需要传递组件。

另请参阅:“Dagger 2用户指南”中的Bindings in the graph