美文网首页
Dagger2详解——最直白易懂、详细的dagger2注入流程原

Dagger2详解——最直白易懂、详细的dagger2注入流程原

作者: FantasySkyland | 来源:发表于2020-07-18 16:30 被阅读0次

项目中有使用dagger2,自己一直处于一个只会套模板使用的状态,项目做完研究了下dagger2注入流程的原理,写一下自己的心得。不熟悉dagger2使用流程的同学可以先去熟悉下使用流程,这里不做具体探讨。

dagger2版本使用的是2.14.1,旧版本生成的代码可能会有所不同,但逻辑基本相同

一、注入流程

1.创建module,这里简单地创建了一个string对象,编译过后就会生成CommonModule_ProvideContentFactory类


图片.png

CommonModule_ProvideContentFactory类 实现了Factory, 泛型是provider返回的对象,构造方法中传入了module对象。其中get()方法调用了module中的provideContent,返回了这个方法的结果


图片.png
2.创建CommonComponent,构建后生成DaggerCommonComponent 以及Dagger2Activity_MembersInjector
图片.png

先看下Dagger2Activity_MembersInjector ,构造方法中传入了利用第一步生成的CommonModule_ProvideContentFactory封装的Provider对象contentProvider,在MembersInjector方法中调用了contentProvider.get(),最终就调用到了module中的方法,并把这个值赋值给需要注入的实例,实例就是Dagger2Activity

public final class Dagger2Activity_MembersInjector implements MembersInjector<Dagger2Activity> {
  private final Provider<String> contentProvider;

   //构造方法中传入contentProvider
  public Dagger2Activity_MembersInjector(Provider<String> contentProvider) {
    this.contentProvider = contentProvider;
  }

  public static MembersInjector<Dagger2Activity> create(Provider<String> contentProvider) {
    return new Dagger2Activity_MembersInjector(contentProvider);
  }

  
  @Override
  public void injectMembers(Dagger2Activity instance) {
    injectContent(instance, contentProvider.get());//contentProvider.get()获取到module实例对象中提供的具体值
  }
 //赋值给注入对象的成员变量
  public static void injectContent(Dagger2Activity instance, String content) {
    instance.content = content;
  }
}
接下来看DaggerCommonComponent和Dagger2Activity

Dagger2Activity ,这里箭头注入了一个string对象,初始化时调用了DaggerCommonComponent的inject方法,调用这个方法后就完成了注入


图片.png

DaggerCommonComponent ,这是注入过程中的一个桥梁。内部定义了一个Builder对象,Builder对象里有我们在CommonComponent里定义的module成员变量,activity调用commonModule对module赋值。
赋值完就调用build返回DaggerCommonComponent实例化对象。DaggerCommonComponent的构造方法里,利用Builder里的module对象 创建第一步里的provider对象 。
再调用DaggerCommonComponent的inject方法,inject方法里调用了Dagger2Activity_MembersInjector 里的静态方法injectContent,对Dagger2Activity里的content赋值,content的值来自provideContentProvider.get(),到这里赋值就完成了

public final class DaggerCommonComponent implements CommonComponent {
  private Provider<String> provideContentProvider;

  private DaggerCommonComponent(Builder builder) {
    initialize(builder);
  }

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

  private Dagger2Presenter getDagger2Presenter() {
    return new Dagger2Presenter(provideViewProvider.get());
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
  
    this.provideContentProvider =
        DoubleCheck.provider(CommonModule_ProvideContentFactory.create(builder.commonModule));
  }

  @Override
  public void inject(Dagger2Activity activity) {
    injectDagger2Activity(activity);
  }

  private Dagger2Activity injectDagger2Activity(Dagger2Activity instance) {
    Dagger2Activity_MembersInjector.injectContent(instance, provideContentProvider.get());
    return instance;
  }

  public static final class Builder {
    private CommonModule commonModule;//在CommonComponent里定义的module

    private Builder() {}

    //返回DaggerCommonComponent实例化对象
    public CommonComponent build() {
      if (commonModule == null) {
        throw new IllegalStateException(CommonModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerCommonComponent(this);
    }
    //activity里调用这个方法对module进行赋值
    public Builder commonModule(CommonModule commonModule) {
      this.commonModule = Preconditions.checkNotNull(commonModule);
      return this;
    }
  }
}

关于DoubleCheck

provider(Provider<T> delegate)调用了构造器方法,构造器中将传入的Provider对象保存起来了,调用get()时会调用保存的provider对象的get(),实际上就是调用工厂方法的get()拿到对象,这样就实现了懒加载,在需要的时候调用get(),这时才会调用工厂方法的get(),因为真正创建对象的细节是封装在工厂类的get()中的,同时,它会将得到的对象缓存起来,这样下次调用就不需要再调用工厂类创建对象了。

public static <T> Provider<T> provider(Provider<T> delegate) {
...    
    return new DoubleCheck<T>(delegate);
}
  
  private DoubleCheck(Provider<T> provider) {
    assert provider != null;
    this.provider = provider;
  }

  @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          result = provider.get();
          /* Get the current instance and test to see if the call to provider.get() has resulted
           * in a recursive call.  If it returns the same instance, we'll allow it, but if the
           * instances differ, throw. */
          Object currentInstance = instance;
          if (currentInstance != UNINITIALIZED && currentInstance != result) {
            throw new IllegalStateException("Scoped provider was invoked recursively returning "
                + "different results: " + currentInstance + " & " + result + ". This is likely "
                + "due to a circular dependency.");
          }
          instance = result;
          /* Null out the reference to the provider. We are never going to need it again, so we
           * can make it eligible for GC. */
          provider = null;
        }
      }
    }
    return (T) result;
  }

流程总结

首先创建好module 和Component 类,以及需要注入的activity,编译后生成相关的类
在activity初始化中调用注入方法,从这行代码开始分析流程

DaggerCommonComponent.builder().commonModule(new CommonModule(this)).build().inject(this);
1.DaggerCommonComponent.builder()获取到Builder对象
2.commonModule(new CommonModule(this)),给Builder力的module成员变量赋值
3.build(),创建了DaggerCommonComponent对象,DaggerCommonComponent的构造方法中利用Builder
里的module对象 创建里的provider对象,provider构造参数是实例化的module,其中get()方法返回module里@provider标记的方法返回值

4.inject(this),调用Dagger2Activity_MembersInjector里的inject方法,inject方法参数一是activity,
参数二是provider.get()获取到的具体值,然后赋值给activity里@inject标记的成员变量

二、关于注入有三种方式

构造方法注入:在类的构造方法前面注释@Inject
成员变量注入:在类的成员变量(非私有)前面注释@Inject
函数方法注入:在函数前面注释@Inject

上面例子说明的是,在类的成员变量(非私有)前面注释@Inject

1.接下去看下在类的构造方法前面注释@Inject
创建present类,需要传入一个view对象,在构造方法注释@Inject


图片.png

dagger2activity中多了一行注入代码


图片.png
module第一步上面已经写好了,编译后生成CommonModule_ProvideViewFactory
Dagger2Activity_MembersInjector中增加了present相关的注入方法,与string 的注入方法一样
图片.png

DaggerCommonComponent中多了present的注入方法,注意在injectDagger2Activity里注入present时调用了getDagger2Presenter,而这个方法里new了一个Dagger2Presenter,参数传的是从provider中获得的view,其他步骤和成员变量注入一样


图片.png
2.在函数前面注释@Inject
dagger2activity中修改,在一个方法中注释@Inject,并把注入的值赋值给content
图片.png
Dagger2Activity_MembersInjector 中箭头处的赋值方法由变量赋值变成了方法调用,其他逻辑不变
图片.png
DaggerCommonComponent里的逻辑没有变化

总结

在类的成员变量(非私有)前面注释@Inject 和在函数前面注释@Inject ,注入的逻辑流程一样,只是赋值时一个是成员变量赋值,一个是调用方法
在类的构造方法前面注释@Inject,Component会增加一个方法new 出这个对象

这里说明一下,我dagger2版本使用的是2.14.1。而在2.11版本里,new出present对象的方法是在provider里,Component里使用的是Dagger2Activity_MembersInjector.injectMembers方法,而不是具体的静态方法,其他逻辑一样

参考文献 https://www.jianshu.com/p/eef7fa8136e7

相关文章

网友评论

      本文标题:Dagger2详解——最直白易懂、详细的dagger2注入流程原

      本文链接:https://www.haomeiwen.com/subject/tnhfkktx.html