上一篇文章介绍了Dagger2的基本用法,这篇文章主要说一下Dagger2中@Scope的用法和原理。

上一篇文章中提到:

如上面例子所示,如果要求D对象为单例,可以通过@Singleton注解来实现。首先我们需要在依赖图中声明对象是单例的:

@Modulepublic class DModule {    @Provides    @Singleton    public D provideD() {        return new D();    }}

DComponent接口也需要声明:

@Singleton@Component(modules = DModule.class)public interface DComponent {    D provideD();}

如此,当我们注入D对象时,可保证每次注入的是同一个D对象:

DComponent dComponent = DaggerDComponent.create();D d1 = dComponent.provideD(); D d2 = dComponent.provideD(); // d1 == d2

在我们看来,只是多加了一个注解而已,便实现了单例模式。要知道其原理,要从Dagger2生成的源码入手。

Dagger2生成的源码

以如下例子为例:

  1. 定义类:

    public class A {    public A(){    }}public class B {    A a;    public B(A a) {        this.a = a;    }}public class C {    A a;    B b;    public C(A a, B b) {        this.a = a;        this.b = b;    }}
  2. 定义Module

    @Modulepublic class ABCModule {    @Provides    public A provideA() {        return new A();    }    @Provides    public B provideB(A a) {        return new B(a);    }    @Provides    public C provideC(A a, B b) {        return new C(a, b);    }}
  3. 定义Component接口:

    @Component(module=ABCModule.class)public interface ABCComponent {    public A provideA();    public B provideB();    public C provideC();    void inject(Main main);}
  4. 依赖注入:

    public class Main {

    @InjectC c;public Main() {    ABCComponent abcComponent = DaggerABCComponent            .builder()            .dComponent(dComponent)            .build();    A a = abcComponent.provideA();    B b = abcComponent.provideB();    abcComponent.inject(this);}

    }

编译工程,Dagger2在项目路径下生成了如下文件:

[dagger2]┣━[di]┃  ┣━[component]┃  ┃  ┗━DaggerABCComponent.java┃  ┗━[module]┃      ┣━ABCModule_ProvideAFactory.java┃      ┣━ABCModule_ProvideBFactory.java┃      ┗━ABCModule_ProvideCFactory.java┗━[model]    ┗━Main_MembersInjector.java

(利用这个工具生成了文件结构图)

注意,生成的文件在关联的类相同路径下。如DaggerABCComponent类生成在ABCComponent路径下。

我们先来看看实际接触到的DaggerABCComponent类:

@Generated("dagger.internal.codegen.ComponentProcessor")public final class DaggerABCComponent implements ABCComponent {  private Provider provideAProvider;  private Provider provideBProvider;  private Provider provideCProvider;  private MembersInjector
mainMembersInjector; private DaggerABCComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static ABCComponent create() { return builder().build(); } private void initialize(final Builder builder) { this.provideAProvider = ABCModule_ProvideAFactory.create(builder.aBCModule); this.provideBProvider = ABCModule_ProvideBFactory.create(builder.aBCModule, provideAProvider); this.provideCProvider = ABCModule_ProvideCFactory.create(builder.aBCModule, provideAProvider, provideBProvider); this.mainMembersInjector = Main_MembersInjector.create(provideCProvider); } @Override public A provideA() { return provideAProvider.get(); } @Override public B provideB() { return provideBProvider.get(); } @Override public C provideC() { return provideCProvider.get(); } @Override public void inject(Main main) { mainMembersInjector.injectMembers(main); } public static final class Builder { private ABCModule aBCModule; private Builder() { } public ABCComponent build() { if (aBCModule == null) { this.aBCModule = new ABCModule(); } return new DaggerABCComponent(this); } public Builder aBCModule(ABCModule aBCModule) { if (aBCModule == null) { throw new NullPointerException("aBCModule"); } this.aBCModule = aBCModule; return this; } }}

来看几个关键点:

  1. DaggerABCComponent继承于ABCComponent。所以我们可以直接调用ABCComponent的方法。

  2. DaggerABCComponent需要Builder来进行初始化。Builder的作用是提供对象的module。

  3. 对象通过Provider从依赖图中取出。Provider由Factory生成时会有类似依赖注入的操作。

  4. 通过MembersInjector进行依赖注入。

这几个关键类的关系可用下图表示:

+---------------------------------------+|         DaggerABCComponent            ||                                       ||  +----------+  create     +-----------+------------+|  |  Factory +-----+-----> |  Provider           ||  +----+-----+     |       +----+------+------------+|       ^           |       |    |      ||       |           |       | +--v------+------------+|       |           +-----> | |Provider           ||       | ABCModule |       | +--+------+------------+|       |           |       |    |      ||       |           |       +----v------+------------+|  +----+----+      +-----> |  Provider           ||  | Builder |              +-----------+------------+|  +---------+                          ||                                       || +--------------------+    +-----------+------------+| |Main_MembersInjector+--> |  MembersInjector
|| +--------------------+ +-----------+------------+| |+---------------------------------------+

其中最最关键的是Factory和Provider。以B类为例,从依赖图中取出B对象,需要经过如下代码:

...this.provideBProvider = ABCModule_ProvideBFactory.create(builder.aBCModule, provideAProvider);...@Overridepublic B provideB() {      return provideBProvider.get();}

其中ABCModule_ProvideBFactory的源码如下所示:

@Generated("dagger.internal.codegen.ComponentProcessor")public final class ABCModule_ProvideBFactory implements Factory {  private final ABCModule module;  private final Provider aProvider;  public ABCModule_ProvideBFactory(ABCModule module, Provider aProvider) { // 根据之前的依赖关系,注入ProviderA      assert module != null;    this.module = module;    assert aProvider != null;    this.aProvider = aProvider;  }  @Override  public B get() {      B provided = module.provideB(aProvider.get()); // 从ProviderA中取出A对象,再生成B对象    if (provided == null) {      throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");    }    return provided;  }  public static Factory create(ABCModule module, Provider aProvider) {      return new ABCModule_ProvideBFactory(module, aProvider);  }}

Factory和Provider接口如下所示:

public interface Factory extends Provider {}public interface Provider {    T get();}

从使用者的角度看,无需关心对象是如何生成的,只需调用provider的get方法即可获得对象。而且对象应该是符合既定的规则并且初始化好可以马上用的。

从ABCModule_ProvideBFactory(或者某个Provider)的角度看,在初始化方法里就明确了自己所需依赖的对象(这里是ProviderA)。在get方法的实现里,只需关心B对象的生成。当需要A对象时,直接从外部“注入”的providerA取出即可。

再来看一看Main_MembersInjector的实现:

@Generated("dagger.internal.codegen.ComponentProcessor")public final class Main_MembersInjector implements MembersInjector
{ private final Provider cProvider; public Main_MembersInjector(Provider cProvider) { assert cProvider != null; this.cProvider = cProvider; } @Override public void injectMembers(Main instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.c = cProvider.get(); } public static MembersInjector
create(Provider cProvider) { return new Main_MembersInjector(cProvider); }}

Dagger2在编译时会分析module中inject方法的参数的类型(这里是Main类),记录下用@Inject注解标注的成员,然后生成对应的Injector。

理解Injector的关键在理解它的构造方法和injectMembers方法。instance.c = cProvider.get();一句实施了依赖注入。

@Singleton

修改ABCModule如下所示:

    @Module    public class ABCModule {        ...        @Provides        @Singleton               // 添加Singleton注解        public B provideB(A a) {            return new B(a);        }        ...    }

修改ABCComponent如下所示:

    @Singleton    @Component(module=ABCModule.class)    public interface ABCComponent {        ...    }

我们来看看Dagger2生成的代码有什么不同:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerABCComponent implements ABCComponent {
...

private Provider provideBProvider;

...

private void initialize(final Builder builder) {

...this.provideBProvider = ScopedProvider.create(ABCModule_ProvideBFactory.create(builder.aBCModule, provideAProvider));...

}

...

@Override
public B provideB() {

return provideBProvider.get();

}

...

}

可以看到唯一的不同是用ScopedProvider将ABCModule_ProvideBFactory包裹起来。来看一下ScopedProvider的源码:

package dagger.internal;import javax.inject.Provider;public final class ScopedProvider implements Provider {  private static final Object UNINITIALIZED = new Object();  private final Factory factory;  private volatile Object instance = UNINITIALIZED;  private ScopedProvider(Factory factory) {    assert factory != null;    this.factory = factory;  }  @SuppressWarnings("unchecked") // cast only happens when result comes from the factory  @Override  public T get() {    // double-check idiom from EJ2: Item 71    Object result = instance;    if (result == UNINITIALIZED) {      synchronized (this) {        result = instance;        if (result == UNINITIALIZED) {          instance = result = factory.get();        }      }    }    return (T) result;  }  /** Returns a new scoped provider for the given factory. */  public static  Provider create(Factory factory) {    if (factory == null) {      throw new NullPointerException();    }    return new ScopedProvider(factory);  }}

理解上面的代码关键在于:

  1. ScopedProvider在dagger.internal下,非Dagger2自动生成。

  2. ScopedProvider也是一个Provider

  3. 利用double-check,在instance上实现了单例模式。也就是说,在ScopedProvider的生命周期内,get返回的都是同一个对象。

以上3点实现了无入侵式的Singleton模式。但其实ScopedProvider并不是专为Singleton模式设计的,Singleton模式只是Dagger2中Scope功能的效果。

@Scope

@Singleton注解的源码如下所示:

@Scope@Documented@Retention(RUNTIME)public @interface Singleton {}...@Target(ANNOTATION_TYPE)@Retention(RUNTIME)@Documentedpublic @interface Scope {}

可以看出,@Singleton只是一个标记,表明这是一个Scope。那么Scope是什么呢?源代码中有如此注释:

A scope annotation applies to a class
containing an injectable constructor and governs how the injector reuses
instances of the type. By default, if no scope annotation is present, the
injector creates an instance (by injecting the type's constructor), uses
the instance for one injection, and then forgets it. If a scope annotation
is present, the injector may retain the instance for possible reuse in a
later injection.

简单地说,@Scope决定了注射器从依赖图中取出对象的行为。如果节点有Scope标签,那么注入时将重用上次生成的对象。

依赖图中某个节点标注了@Scope后,便拥有了与当前Component相同的生命周期。也就是说,如果要实现全局(Application范围内)的Singleton,必需要有全局的Component。这就是为什么许多其他关于Dagger2的例子中,要在Application中保持ApplicationComponent的引用的原因。

至于在许多例子中看到的@PerActivity(对象在当前Activity的生命周期内唯一),@PerUser(对象在当前用户态销毁前唯一),它们的实现也是依赖于Component的生命周期。所以需要在Activity的onCreate中新建SomeActivityComponent并保持引用,在UserManager的login中新建UserComponent并保持引用。

更多相关文章

  1. android定制化显示toast
  2. Android(安卓)的 Application 初始化
  3. Android(安卓)Json的使用(1) 使用jsonschema2pojo生成class文件
  4. Android中的内部类引起的内存泄露
  5. Android(安卓)依赖库的使用
  6. ButterKnife代码生成的插件
  7. Android——application全局类的使用
  8. iOS开发之初识UITableView
  9. 活用Android线程间通信的Message机制

随机推荐

  1. 在android jni中使用log
  2. Android:时间控件
  3. android各个文件分析
  4. 创建Android SD卡遇到的问题
  5. CyanogenMod | Android Community Rom ba
  6. Android开发中ConnectivityManager应用
  7. android最新源码下载
  8. ListView详解
  9. 使用Android自带Ant构建Apk
  10. Android基础之基本控件