Dagger2的使用与理解(1)

来源:互联网 发布:简单优化模板源码下载 编辑:程序博客网 时间:2024/06/09 21:56

本篇是我写博客的第一篇,基于自己表达能力太差于是就想通过写博客来提高自己,表达可能会相当乱,自己本身水平一般般,如果有啥错误欢迎大家指出,如果能帮到大家那就是我最大的收获。

最近写项目的时候听学长的建议用了下Dagger2这个框架,发现这个框架特别好用,感觉整个项目的逼格就上去了。不过Dagger2在使用上还是有一点难度,当然可能对我这种新手而言,大神分分钟拿来使用。Dagger2也是谷歌官方推荐使用的框架。那么Dagger2是什么:

dagger2是一个基于JSR-330标准的依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。这句话看起来很官方,没错这是我在其他博客复制粘贴的。简单说就是通过这个框架,你不在用new来创建对象,而是写个注解@Inject就初始化好对象了。所谓的依赖就是:

A a = new A(B b);

我们就可以说b是a的依赖,因为预要创建a,需先创建b。我们想一下平时在Activity上是不是有很多成员变量,这些成员变量都是Activity的依赖,通常我们写一个Init()函数专用来初始化成员变量,如果这些成员变量又依赖于其他变量如像A这种,那我们还得先实例化B类对象。

public class DaggerActivity extends AppCompatActivity {    A a1;    A a2;    A a3;    A a4;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();    }    private void init() {        B b1 = new B();        a1 = new A(b1);        B b2 = new B();        a1 = new A(b2);        B b3 = new B();        a1 = new A(b3);        B b4 = new B();        a1 = new A(b4);    }}

这就尴尬了一下好多行代码,看着极不舒服。如果使用Dagger2则变成这样子:

public class DaggerActivity extends AppCompatActivity {    @Inject    A a1;    @Inject    A a2;    @Inject    A a3;    @Inject    A a4;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        DaggerActivityComponent.create().inject(this);    }}

搞定。。。是不是很简洁明了

那么首先介绍下Dagger2最重要的几个注解

@Component:用这个注解修饰的叫做注入器,这个注解只能修饰接口和抽象类,通过注入器结合@Inject注解就能完成依赖的注入。如上代码:

@InjectA a1;DaggerActivityComponent.create().inject(this);

DaggerActivityComponent这个就是注入器的实现类,通过inject()方法,参数是Activity,为自己的依赖实现注入。注入哪些依赖用@Inject标识,这样就成功地将a1注入。所以@Inject的作用是

  • 标记哪些依赖是我们要注入的
  • 标记哪些要生成哪些依赖

第二点可以请看A和B类的代码

A类代码

public class A {    private String name;    private int id;    @Inject    public A(B b) {    }    //...省略get,set方法}

B类代码

public class B {    private String name;    private int id;    @Inject    public B() {    }    //...省略get,set方法}

A的构造器和B的构造器用@Inject标记,说明可以生成A类的依赖和B类的依赖。这里发现生成A类的对象依赖于B类对象,很明显注入器在注入A类对象的时候,肯定会先生成B类依赖,然后再注入。
看到这里可能大家有个疑问了,DaggerActivityComponent这个东西是怎么生成的,以及他是怎么实现依赖的注入的。我之前说@Component只能修饰接口和抽象类,下面是我写的接口:

@Componentpublic interface ActivityComponent {    void inject(DaggerActivity daggerActivity);}

那么DaggerActivityComponent肯定和这个接口有关,实际上DaggerActivityComponent是利用APT注解处理工具动态生成的代码,你会发现你在module添加dependencies会添加一个东西:

apt 'com.google.dagger:dagger-compiler:2.0'

那么DaggerActivityComponent这个类在哪呢,如下图:切换到Project模式
这里写图片描述

DaggerActivityComponent 代码如下:

@Generated("dagger.internal.codegen.ComponentProcessor")public final class DaggerActivityComponent implements ActivityComponent {  private Provider<A> aProvider;  private MembersInjector<DaggerActivity> daggerActivityMembersInjector;  private DaggerActivityComponent(Builder builder) {      assert builder != null;    initialize(builder);  }  public static Builder builder() {      return new Builder();  }  public static ActivityComponent create() {      return builder().build();  }  private void initialize(final Builder builder) {      this.aProvider = A_Factory.create(B_Factory.create());    this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);  }  @Override  public void inject(DaggerActivity daggerActivity) {      daggerActivityMembersInjector.injectMembers(daggerActivity);  }  public static final class Builder {    private Builder() {      }    public ActivityComponent build() {        return new DaggerActivityComponent(this);    }  }}

DaggerActivityComponent类有Provider的成员变量,它是个接口,内容提供者,可以通过get()方法获取A的实例对象。

public interface Provider<T> {    T get();}

DaggerActivityComponent还有个MembersInjector类,这个是成员注入器,也是个接口,上面调用DaggerActivityComponent.inject()方法实际上是调用MembersInjector的inject()方法。

public interface MembersInjector<T> {  void injectMembers(T instance);}

我们知道依赖的注入是通过DaggerActivityComponent.create().inject(this)开始的,我们来看一下他的流程:

  • DaggerActivityComponent里有个Builder对象,可见他是通过建造者模式去构建对象,先create()生成一个Builder,在调用Builder.builder(),最后还是调用了
private DaggerActivityComponent(Builder builder) {      assert builder != null;    initialize(builder);  }

为什么要绕这么一圈呢 心好累,然后调用initialize()

private void initialize(final Builder builder) {      this.aProvider = A_Factory.create(B_Factory.create());    this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);  }

在这个方法中,初始化成员注入器和内容提供者,A_Factory是Factory接口的实现,Factory又继承Provider - - 什么方法都没有,你又在逗我

public interface Factory<T> extends Provider<T> {}public final class A_Factory implements Factory<A> {  private final Provider<B> bProvider;  public A_Factory(Provider<B> bProvider) {      assert bProvider != null;    this.bProvider = bProvider;  }  @Override  public A get() {      return new A(bProvider.get());  }  public static Factory<A> create(Provider<B> bProvider) {      return new A_Factory(bProvider);  }}

调用A_Factory.create()方法完成对A_Factory的创建,注意这里传入了B_Factory,因为B是A的依赖,创建A时候需要用到B,所以A_Factory含有一个B_Factory的成员变量,同时重写Provider的get()方法,return new A(bProvider.get()), B_Factory与此类似只是直接返回B的实例。
因为每一次都返回new 出来的对象,所以一个类中的注入相同的依赖,每个依赖都是新的对象,而不是同一个对象,当然dagger2可以实现单例,这个在下面再说。
然后是成员注入器的生成,第一参数是MembersInjectors.noOp()的返回值,它是一个空实现的MembersInjector,表示注入已经到达父类的最顶端,第二个参数是A类的内容提供者。

this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);@SuppressWarnings("unchecked")  public static <T> MembersInjector<T> noOp() {    return (MembersInjector<T>) NoOpMembersInjector.INSTANCE;  }  private static enum NoOpMembersInjector implements MembersInjector<Object> {    INSTANCE;    @Override public void injectMembers(Object instance) {      if (instance == null) {        throw new NullPointerException();      }    }  }

最后调用inject(DaggerActivity daggerActivity)方法,实质上是调用daggerActivityMembersInjector.injectMembers(daggerActivity),
它首先判断一下空,然后调用父类的注入器为父类注入依赖,因为这边父类没有@inject标识的依赖,所以父类注入器supertypeInjector就是我们之前传入的空实现的MembersInjectors.noOp()的返回值。然后为DaggerActivity 的成员变量A注入依赖,因为这边是直接通过对象引用a,所以成员变量不能用private修饰。这样就为DaggerActivity的成员变量依赖注入好实例。

//a1AndA2AndA3AndA4Provider是上面传入的Provider<A>  public void injectMembers(DaggerActivity instance) {      if (instance == null) {      throw new NullPointerException("Cannot inject members into a null reference");    }    supertypeInjector.injectMembers(instance);    instance.a1 = a1AndA2AndA3AndA4Provider.get();    instance.a2 = a1AndA2AndA3AndA4Provider.get();    instance.a3 = a1AndA2AndA3AndA4Provider.get();    instance.a4 = a1AndA2AndA3AndA4Provider.get();  }

@Inject还可以修饰在方法上面,为方法里的参数注入依赖

    @Inject    public void setA(A a){        //a 已经注入依赖 可以对a进行操作    }

对应的实际注入代码

 instance.setA(a1AndA2AndA3AndA4AndAProvider.get());

如果我们要注入依赖的类的父类有@Inject标识,比如我们通常会让Activity继承一个BaseActivity,我们在BaseActivity里注入一个B类对象,那么上面注入器的构建就会传入父类的一个注入器,注入时,先注入父类的依赖,再注入子类的依赖。

//DaggerActivityComponent里多了个BaseActivity_MembersInjector成员变量,并在initialize初始化,传入DaggerActivity_MembersInjector。private void initialize(final Builder builder) {      this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), B_Factory.create());    this.aProvider = A_Factory.create(B_Factory.create());    this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(baseActivityMembersInjector, aProvider);  }//注入时,先调用supertypeInjector.injectMembers(instance),supertypeInjector就是传入的BaseActivity_MembersInjector@Override  public void injectMembers(DaggerActivity instance) {      if (instance == null) {      throw new NullPointerException("Cannot inject members into a null reference");    }    supertypeInjector.injectMembers(instance);    instance.a1 = a1AndA2AndA3AndA4AndAProvider.get();    instance.a2 = a1AndA2AndA3AndA4AndAProvider.get();    instance.a3 = a1AndA2AndA3AndA4AndAProvider.get();    instance.a4 = a1AndA2AndA3AndA4AndAProvider.get();    instance.setA(a1AndA2AndA3AndA4AndAProvider.get());  }

通常我们要注入的依赖里还有要注入的依赖,比如A类里面有个B类的成员变量

public class A {    private String name;    private int id;    @Inject    B b1;    @Inject    public A(B b) {    }    //...省略get,set方法}

这时候DaggerActivityComponent又多了A_MembersInjector,构造传入B_Factory.create(),这个注入器就是用来为A注入B类的依赖。

private void initialize(final Builder builder) {      this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), B_Factory.create());    this.aMembersInjector = A_MembersInjector.create(B_Factory.create());    this.aProvider = A_Factory.create(aMembersInjector, B_Factory.create());    this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(baseActivityMembersInjector, aProvider);  }

A类注入器传入A的Provider对象里,在A的get()方法里我们还是先生成A类对象,再调用注入器注入,注意 :membersInjector就是我们上面传入的A类注入器,调用injectMembers()方法,为B类依赖注入对象。

@Override  public A get() {      A instance = new A(bProvider.get());    membersInjector.injectMembers(instance);    return instance;  }  @Override  public void injectMembers(A instance) {      if (instance == null) {      throw new NullPointerException("Cannot inject members into a null reference");    }    instance.b1 = b1Provider.get();  }

注意:不能循环注入:在A类里面在注入一个A类依赖,这个将会导致一直注入下去,编译会出错。

//不能循环注入//    @Inject//    A a1;

最后简单的总结一下,只要有@Inject标识,就会对应生成相应的MembersInjector,如果要注入的类有父类要注入,先注入父类,在注入子类,最后注意不能循环注入。

  • -讲的很罗嗦,大家看看就好,下面几篇依次说下另外几个注解:@Scope,@Module, @Provides, @SubComponent, @Qualifier和@Named。
1 0