Dagger2源码解析inject过程

2020-11-22 23:25:56

参考地址 Android开发之Dagger2--源码角度分析inject过程(二)

前言

在上一篇文章中 Android开发之Dagger2的基本使用(一),主要是在项目了里导入了Dagger2,并注入成功,实现了基本的功能。在上一篇文章的末尾也提出了几个问题

  • 添加inject后,通过编译生成的DaggerMainComponent类来导入,说明编译以后生成了一些类,那到底生成了什么类呢。

  • Module和Component又是什么,该怎么里理解
    在这篇文章后里将一一讨论。

引入Dagger2后生成的类

对项目进行编译以后,我们打开app的build目录,我的是在app\build\generated\source\apt\debug\com\jackson\daggertest下,可以看到引入Dagger2后生成的类,一共有三个,分别是 Student_Factory.java,DaggerMainComponent.java,Daggertest1Activity_MembersInjector.java,我们一步步来。


    1. Student_Factory.java,对Student的构造方法用@Inject注解后编译生成

public final class Student_Factory implements Factory<Student> {
  private static final Student_Factory INSTANCE = new Student_Factory();

  @Override
  public Student get() {
    return new Student();
  }

  public static Student_Factory create() {
    return INSTANCE;
  }}

不难看出这实际上是一个工厂类,create()方法提供工厂实例,get()获取Studnet的对象。也就是说我们对一个类的构造方法用@Inject注解后,会生成一个提供该类实例的类。

  • 2 DaggerMainComponent.java
    源码如下:

public final class DaggerMainComponent implements MainComponent {
  private DaggerMainComponent(Builder builder) {}

  public static Builder builder() {
    return new Builder();
  }

  public static MainComponent create() {
    return new Builder().build();
  }

  @Override
  public void inject(Daggertest1Activity daggertest1Activity) {
    injectDaggertest1Activity(daggertest1Activity);
  }

  private Daggertest1Activity injectDaggertest1Activity(Daggertest1Activity instance) {
    Daggertest1Activity_MembersInjector.injectMStudent(instance, new Student());
    return instance;
  }

  public static final class Builder {
    private Builder() {}

    public MainComponent build() {
      return new DaggerMainComponent(this);
    }

    /**
     * @deprecated This module is declared, but an instance is not used in the component. This
     *     method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
     */
    @Deprecated
    public Builder mainModule(MainModule mainModule) {
      Preconditions.checkNotNull(mainModule);
      return this;
    }
  }}

很明显,这是我们在Activity里调用的,类名很简单,就是Dagger+Component的名字,Activity里的调用代码如下:

DaggerMainComponent.builder()
                .mainModule(new MainModule())
                .build()
                .inject(this);

结合源码可以看到,DaggerMainComponent是通过Builder模式新建了一个DaggerMainComponent的对象,当DaggerMainComponent的对象执行inject()方法时,会最终执行Daggertest1Activity_MembersInjector的injectMStudent()方法,参数为this,既当前的Activity的实例,我们继续往下看。

3 Daggertest1Activity_MembersInjector.java

public final class Daggertest1Activity_MembersInjector
    implements MembersInjector<Daggertest1Activity> {
  private final Provider<Student> mStudentProvider;

  public Daggertest1Activity_MembersInjector(Provider<Student> mStudentProvider) {
    this.mStudentProvider = mStudentProvider;
  }

  public static MembersInjector<Daggertest1Activity> create(Provider<Student> mStudentProvider) {
    return new Daggertest1Activity_MembersInjector(mStudentProvider);
  }

  @Override
  public void injectMembers(Daggertest1Activity instance) {
    injectMStudent(instance, mStudentProvider.get());
  }

  public static void injectMStudent(Daggertest1Activity instance, Student mStudent) {
    instance.mStudent = mStudent;
  }}

上面提到,当在Activity执行injec方法时,会最终执行到这个类的injectMStudent()方法,其中传递过来了Activity的实例,那么是怎么将Activity的mStudent和Student_Factory提供的Student实例联系起来呢。

 public static void injectMStudent(Daggertest1Activity instance, Student mStudent) {
    instance.mStudent = mStudent;
  }

通过这个方法,我们可以看到,传递过来的instance里的mStudnet被赋值了一个mStudent对象,那么我们猜测,这个mStudent就是从Student_Factory传递过来的,到底是不是呢,我们继续验证。

 @Override
  public void injectMembers(Daggertest1Activity instance) {
    injectMStudent(instance, mStudentProvider.get());
  }

injectMStudent()方法在这个地方调用,其中传递过来的是mStudentProvider.get(),在看一下这个mStudentProvider的定义,private final Provider<Student> mStudentProvider; 这个应该就是在Student_Factory里提供的工厂类。
不信看一下

public interface Factory<T> extends Provider<T> {}

Factory的父类正是Provider,mStudentProvider.get()就是获取的是Student_Factory的Student对象,然后和instnce里的对象进行赋值;

@Override
  public Student get() {
    return new Student();
  }

综上,通过生成的类,我们一步步追踪到了,当对一个类吃的构造方法使用@Inject注解

@Inject
    public Student(){

    }

在Activity里,执行注入操作后

@Inject
    Student mStudent;  // 注入Studnet的实例

  DaggerMainComponent.builder()
                .mainModule(new MainModule())
                .build()
                .inject(this);

Activity里的mStudent是怎么和Student的实例联系起来的。
总结起来就是一下几点:

  • 1 通过工厂方法提供类的实例

  • 2 生成Dagger+Component名字的类,通过Builder模式提供该类的实例

  • 3 执行inject方法时建立实例之间的联系

下篇文章再讨论 Module和Component。

  • 2018-12-10 00:57:37

    Android沉浸式状态栏(透明状态栏)最佳实现

    在Android4.4之前,我们的应用没法改变手机的状态栏颜色,当我们打开应用时,会出现上图中左侧的画面,在屏幕的顶部有一条黑色的状态栏,和应用的风格非常不协调;为了提供更好的界面交互,google在Android4.4以后提供了设置沉浸式状态栏的方法,对于沉浸式状态栏这个名字存在争议,我们不做讨论,实际的效果其实就是透明的状态栏,然后在状态栏的位置显示我们自定义的颜色,通常为应用的actionbar的颜色,或者是将应用的整体的一张图片也占据到状态栏中,如下图所示:

  • 2018-12-11 10:20:40

    Android下载图片到相册

    调用以上系统自带的方法会把bitmap对象保存到系统图库中,但是这种方法无法指定保存的路径和名称,上述方法的title、description参数只是插入数据库中的字段,真实的图片名称系统会自动分配。 或者

  • 2018-12-11 15:45:00

    Laravel中七个非常有用但很少人知道的Carbon方法

    在编写PHP应用时经常需要处理日期和时间,Carbon继承自 PHP DateTime 类的 API 扩展,它使得处理日期和时间更加简单,这篇文章主要给大家分享了Laravel中七个非常有用但很少人知道的Carbon方法,需要的朋友可以参考下。

  • 2018-12-13 11:41:23

    Android drawable微技巧,你所不知道的drawable的那些细节

    好像有挺久时间没更新博客了,最近我为了准备下一个系列的博客,也是花了很长的时间研读源码。很遗憾的是,下一个系列的博客我可能还要再过一段时间才能写出来,那么为了不至于让大家等太久,今天就给大家更新一篇单篇的文章,讲一讲Android drawable方面的微技巧。

  • 2018-12-13 17:14:41

    Android安全开发之浅谈密钥硬编码

    在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码、文件中,这样做会引起很大风险。信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文;对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名。

  • 2018-12-13 17:17:02

    轻松实现动态获取Android手机CPU架构类型

    .so文件是unix的动态连接库,是二进制文件,作用相当于windows下的.dll文件。 他使用了C/C++代码编写的可以操作硬件比java更高级的 底层代码,执行速度和效率比其他语言要高。 在Android中调用动态库文件(*.so)都是通过jni的方式。