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

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

我的模块:

@Module public class App { @Provides @Singleton ThingA provideThingA(){ return new ConcreteThingA(); } } 

在singleton中我想要的东西的界面:

 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只是一个愚蠢的名字,在我的实际应用程序中,我希望在我的服务上有这种单例行为。

调试截图

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

另请参阅:Dagger 2用户指南中的图表中的绑定