美文网首页Android
android IOC框架之Dagger

android IOC框架之Dagger

作者: android源码探索 | 来源:发表于2020-02-03 21:24 被阅读0次

    欢迎大家下载我个人开发的app安琪花园

    Dagger源码地址
    Dagger实战地址

    主要带着如下几个问题对dagger进行了解

    1. 面向对象的六大原则是什么
    2. dagger使用场景
    3. dagger原理

    面向对象的六大原则


    1. 依赖倒置原则
    2. 迪米特原则
    3. 单一职责原则
    4. 接口隔离原则
    5. 里氏替换原则
    6. 开闭原则

    而Dagger 是属于依赖注入, 对象的初始化不放在类里面初始化,
    而是通过注入的方式,可以说是属于面向对象里面的开闭原则。
    而Dagger能解决解耦的问题。当对Model修改的时候 只需要修改一个地址即可

    通过一张效果图来看一下Dagger的工作原理

    image.png

    上图的只是说明了Dagger的一个原理。
    比如:Activity里面有一个Student的属性。
    而这个属性的初始化不是直接放在Activity里面初始化的
    而是委托了Dagger来初始化的。

    而Dagger 具体是如何对属性初始化的呢


    image.png

    上面这个效果图对Dagger的工作流程体现得淋漓尽致
    可以简单理解为:
    Student对象通过包裹后转成Module经Component运送到Activity
    从而完成了初始化的工作。

    为什么要用Dagger来初始化呢


    起初是不是觉得Dagger对对象的初始化反而变得复杂了。
    对于只有一个页面来说确实复杂了。直接在Activity里面初始化多方便呢
    但是反过来说, 如果有成千上万个Activity里面都有对Student初始化呢
    那就在所有的Activity里面把对象给New出来,
    但是如果有一天Student的构造方法改变了,
    那是不是所有的Activity里面都得去调整。
    是不是觉得很麻烦呢?
    这个时候Dagger就能派上用场了。 只需要修改一次就能达到事半功倍的效果。

    Dagger具体是怎么用的呢?


    首先在build.gradle里面添加依赖

     implementation "com.google.dagger:dagger:2.4"
     annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
    

    假若我项目里面有多个Activity里面需要用到Student的实体类

    public class Student {
        String name = "liu";
        Student(int value) {
        }
    }
    

    Activity 要委托Dagger来初始化对象, 肯定需要提供一个获取对象的方法:

    @Module
    public class StudentModule {
    
        @Provides
        public Student getStudent() {
            return new Student(99);
        }
    }
    

    补充一点
    在Dagger的使用必须要创建一个Module, 也就是上面的一个类, 其扮演了上面图片上面的Module的角色, 这个类必须要添加Module注解, 这样Dagger里面的注解处理器才能找到StudentModule

    编译后经过注解处理器后 会生成如下的类

    @Generated(
      value = "dagger.internal.codegen.ComponentProcessor",
      comments = "https://google.github.io/dagger"
    )
    public final class StudentModule_GetStudentFactory implements Factory<Student> {
      private final StudentModule module;
    
      public StudentModule_GetStudentFactory(StudentModule module) {
        assert module != null;
        this.module = module;
      }
    
      @Override
      public Student get() {
        return Preconditions.checkNotNull(
            module.getStudent(), "Cannot return null from a non-@Nullable @Provides method");
      }
    
      public static Factory<Student> create(StudentModule module) {
        return new StudentModule_GetStudentFactory(module);
      }
    }
    

    该类其实就是通过工厂模式来生产Student类, 通过create方法得到 StudentModule_GetStudentFactory实例, 然后调用get方法即可得到Student实例了

    既然Activity里面的Student属性的初始化是委托给Dagger初始化的,
    那么肯定需要将当前Activity注入到Dagger中,
    首先需要定义一个接口, 并添加注解Component
    这个接口就 扮演了上面 图片中的Component角色

    @Component(modules = StudentModule.class) // 快递员拿到了包裹
    public interface StudentComponent {
        // 送到收货地址 --- 注入到Activity
        void injectMainActivity(MainActivity mainActivity); // 不支持多态功能的
    
        void injectMainActivity(MainActivity2 mainActivity);
    
        void injectMainActivity(MainActivity3 mainActivity);
    
        void injectMainActivity(MainActivity4 mainActivity);
    }
    

    编译后经过注解处理器后 会生成如下的类

    @Generated(
      value = "dagger.internal.codegen.ComponentProcessor",
      comments = "https://google.github.io/dagger"
    )
    public final class DaggerStudentComponent implements StudentComponent {
      private Provider<Student> getStudentProvider;
    
      private MembersInjector<MainActivity> mainActivityMembersInjector;
    
      private MembersInjector<MainActivity2> mainActivity2MembersInjector;
    
      private MembersInjector<MainActivity3> mainActivity3MembersInjector;
    
      private MembersInjector<MainActivity4> mainActivity4MembersInjector;
    
      private DaggerStudentComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      public static StudentComponent create() {
        return builder().build();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.getStudentProvider = StudentModule_GetStudentFactory.create(builder.studentModule);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(getStudentProvider);
    
        this.mainActivity2MembersInjector = MainActivity2_MembersInjector.create(getStudentProvider);
    
        this.mainActivity3MembersInjector = MainActivity3_MembersInjector.create(getStudentProvider);
    
        this.mainActivity4MembersInjector = MainActivity4_MembersInjector.create(getStudentProvider);
      }
    
      @Override
      public void injectMainActivity(MainActivity mainActivity) {
        mainActivityMembersInjector.injectMembers(mainActivity);
      }
    
      @Override
      public void injectMainActivity(MainActivity2 mainActivity) {
        mainActivity2MembersInjector.injectMembers(mainActivity);
      }
    
      @Override
      public void injectMainActivity(MainActivity3 mainActivity) {
        mainActivity3MembersInjector.injectMembers(mainActivity);
      }
    
      @Override
      public void injectMainActivity(MainActivity4 mainActivity) {
        mainActivity4MembersInjector.injectMembers(mainActivity);
      }
    
      public static final class Builder {
        private StudentModule studentModule;
    
        private Builder() {}
    
        public StudentComponent build() {
          if (studentModule == null) {
            this.studentModule = new StudentModule();
          }
          return new DaggerStudentComponent(this);
        }
    
        public Builder studentModule(StudentModule studentModule) {
          this.studentModule = Preconditions.checkNotNull(studentModule);
          return this;
        }
      }
    }
    
    

    通过如下的方法将当前的Activity委托给Dagger,
    只需要在Activity的onCreate方法里面调用如下的一句代码
    这样Activity里面的student属性就已经赋值了

    DaggerStudentComponent.create().injectMainActivity(this);
    

    Dagger是怎么知道获取的Student实例赋值给Activity的哪一个属性呢
    这就需要添加Inject注解

     @Inject
        Student student;
    

    编译后经过注解处理器后 会生成如下的类

    @Generated(
      value = "dagger.internal.codegen.ComponentProcessor",
      comments = "https://google.github.io/dagger"
    )
    public final class MainActivity2_MembersInjector implements MembersInjector<MainActivity2> {
      private final Provider<Student> studentProvider;
    
      public MainActivity2_MembersInjector(Provider<Student> studentProvider) {
        assert studentProvider != null;
        this.studentProvider = studentProvider;
      }
    
      public static MembersInjector<MainActivity2> create(Provider<Student> studentProvider) {
        return new MainActivity2_MembersInjector(studentProvider);
      }
    
      @Override
      public void injectMembers(MainActivity2 instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.student = studentProvider.get();
      }
    
      public static void injectStudent(MainActivity2 instance, Provider<Student> studentProvider) {
        instance.student = studentProvider.get();
      }
    }
    
    

    说到这里Dagger的接入到这里就已经结束了

    接下来剖析一下,这句代码是如何就对student初始化的DaggerStudentComponent.create().injectMainActivity(this);

    其可分为两步:

    第一步: 调用create方法

    第二步: 调用injectMainActivit方法

    第一步:

    public static StudentComponent create() {
        return builder().build();
      }
    
    builder()方法得到的是Builder实例, 调用build()方法会初始化一个StudentModule
    然后得到DaggerStudentComponent实例
    
    public StudentComponent build() {
          if (studentModule == null) {
            this.studentModule = new StudentModule();
          }
          return new DaggerStudentComponent(this);
        }
    
    而DaggerStudentComponent的构造方法里面做了一些初始化操作, 调用 如下的方法
    
     private void initialize(final Builder builder) {
    
        this.getStudentProvider = StudentModule_GetStudentFactory.create(builder.studentModule);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(getStudentProvider);
      }
    
    首先会得到getStudentProvider实例, 其实就是注解处理器生成的
    StudentModule_GetStudentFactory类的实例, 这个类的作用就是生产Student实例
    然后对Inject注解生成的类调用create方法,后加值赋值给mainActivityMembersInjector
    

    第二步

    @Override
      public void injectMainActivity(MainActivity mainActivity) {
        mainActivityMembersInjector.injectMembers(mainActivity);
      }
    
    其主要看injectMembers方法体
     public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.student = studentProvider.get();
      }
    
    在这个方法里面就已经看到了student的初始化了
    

    整个项目里面对student的初始化就已经说明白了。

    思考

    **
    上面的代码里面只是通过Dagger来对一个Student初始化
    那如果,我要通过Dagger来对一个Map, 或者Set初始化
    那应该如何实现呢
    **

    将目光聚集到StudentModule类上面, 会发现getStudent方法上面添加了Provides注解

    @Documented @Target(METHOD) @Retention(RUNTIME)
    public @interface Provides {
      enum Type {
        UNIQUE,
        SET,
        SET_VALUES,
        @Beta
        MAP;
      }
    
      Type type() default Type.UNIQUE;
    }
    

    这里面定义了一个枚举类型, 而上面的代码只是测了UNIQUE这种类型,
    对于其它的类型,大家可以举一反三,亲自试试。

    其它文章:
    android 面试题
    android 自定义阴影 ShadowView
    android EventBus源码阅读
    自定义DialogViewLayout 实现Dialog效果

    关注公众号每天会更新一道面试题:

    qrcode_for_gh_c78cd816dc53_344.jpg

    相关文章

      网友评论

        本文标题:android IOC框架之Dagger

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