Dagger2的使用与理解(1)

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

最近写项目的时候听学长的建议用了下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注解就能完成依赖的注入。如上代码:

@Inject
A 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只能修饰接口和抽象类,下面是我写的接口:

@Component
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值