多个实例中的 Dagger 2 单例

Dagger 2 singleton in multiple instances

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

诀窍是 Dagger 通过组件强制执行 scope/lifecycle,而您在这里创建了两个单独的组件:

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 组件并不是绕过它的方法。相反,请尝试以下操作之一:

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

另请参阅:Bindings in the graph 来自 Dagger 2 用户指南