代码之家  ›  专栏  ›  技术社区  ›  why_vincent

多个实例中的匕首2单例

  •  5
  • why_vincent  · 技术社区  · 8 年前

    我刚刚测试了匕首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 回复  |  直到 8 年前
        1
  •  16
  •   Jeff Bowman    8 年前

    诀窍是Dagger通过组件强制实施范围/生命周期,您在这里创建了两个单独的组件:

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

    每次创建新的顶级@Singleton注释组件时,Dagger都会为每个@Singleon对象创建一个全新的对象图,其中包含一个全新容器。您应该改为:

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

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


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

    另请参见: Bindings in the graph 摘自《匕首2用户指南》