我刚刚测试了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只是一个愚蠢的名字,在我的实际应用中,我希望在我的服务上有这种单身行为。
答案 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 Provider<T> tProvider
而不是@Inject YourComponent
只能调用YourComponent.getT
。 另请参阅:“Dagger 2用户指南”中的Bindings in the graph