美文网首页
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