转载

Dagger2 入门 2

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

@Singleton

上一篇文章中提到:

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

@Module

public class DModule {

@Provides

@Singleton

public D provideD() {

return new D();

}

}

DComponent接口也需要声明:

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

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

DComponentdComponent = 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
    @Module
    public 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(Mainmain);
    }
     
    
  4. 依赖注入:
    public class Main {
        @Inject
        C c;
     
        public Main() {
            ABCComponentabcComponent = 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<A> provideAProvider;
  private Provider<B> provideBProvider;
  private Provider<C> provideCProvider;
  private MembersInjector<Main> mainMembersInjector;
 
  private DaggerABCComponent(Builderbuilder) {  
    assert builder != null;
    initialize(builder);
  }
 
  public static Builderbuilder() {  
    return new Builder();
  }
 
  public static ABCComponentcreate() {  
    return builder().build();
  }
 
  private void initialize(final Builderbuilder) {  
    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(Mainmain) {  
    mainMembersInjector.injectMembers(main);
  }
 
  public static final class Builder {
    private ABCModuleaBCModule;
 
    private Builder() {  
    }
 
    public ABCComponentbuild() {  
      if (aBCModule == null) {
        this.aBCModule = new ABCModule();
      }
      return new DaggerABCComponent(this);
    }
 
    public BuilderaBCModule(ABCModuleaBCModule) {  
      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<A>          |
|  +----+-----+    |      +----+------+------------+
|      ^          |      |    |      |
|      |          |      | +--v------+------------+
|      |          +-----> | |Provider<B>          |
|      | ABCModule |      | +--+------+------------+
|      |          |      |    |      |
|      |          |      +----v------+------------+
|  +----+----+      +-----> |  Provider<C>          |
|  | Builder |              +-----------+------------+
|  +---------+                          |
|                                      |
| +--------------------+    +-----------+------------+
| |Main_MembersInjector+--> |  MembersInjector<Main> |
| +--------------------+    +-----------+------------+
|                                      |
+---------------------------------------+
 

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

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

ABCModule_ProvideBFactory的源码如下所示:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class ABCModule_ProvideBFactory implements Factory<B> {
  private final ABCModulemodule;
  private final Provider<A> aProvider;
 
  public ABCModule_ProvideBFactory(ABCModulemodule, Provider<A> 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<B> create(ABCModulemodule, Provider<A> aProvider) {  
    return new ABCModule_ProvideBFactory(module, aProvider);
  }
}
 

Factory和Provider接口如下所示:

public interface Factory<T> extends Provider<T> {
}
 
public interface Provider<T> {
    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<Main> {
  private final Provider<C> cProvider;
 
  public Main_MembersInjector(Provider<C> cProvider) {  
    assert cProvider != null;
    this.cProvider = cProvider;
  }
 
  @Override
  public void injectMembers(Maininstance) {  
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.c = cProvider.get();
  }
 
  public static MembersInjector<Main> create(Provider<C> cProvider) {  
      return new Main_MembersInjector(cProvider);
  }
}
 

@Scope

@Component和Subcomponent

我是怎么用Dagger2的

总结

原文  http://legendmohe.net/2016/08/22/android-dagger2-入门-2/
正文到此结束
Loading...