多个实例中的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用户指南中的图表中的绑定