美文网首页Android技术知识Android开发经验谈Android开发
Android学习进阶——Dagger 2 使用及原理

Android学习进阶——Dagger 2 使用及原理

作者: 谁动了我的代码 | 来源:发表于2022-12-30 21:02 被阅读0次

    概述

    Dagger 2 是 Google 开源的一款依赖注入框架,它的前身是 square 的 Dagger 1,Dagger 2 在 Android 中有着较为广泛的应用。

    Dagger 2 基于 Java 注解,采用 annotationProcessor(注解处理器) 在项目编译时动态生成依赖注入需要的 Java 代码,然后我们在合适的位置手动完成最终的依赖注入,而不是 Dagger 1 中基于反射的解决方案,所以在性能上是有保障的。

    Dagger2的使用

    首先我先用张图来简单说明一下Dagger2使用的流程


    图中的Module是应用中常用的功能模块,比如说网络访问,数据存储等。这个类会有一个@Module的注解,具体的代码我会在后面详细介绍。其实这个Module的作用是提供各种功能对象,而这些Module会放到一个有@Component的容器类中,也就是图中Component类。当我们想使用各种功能对象进行业务操作的时候,只需要这个容器就能得到被注册了的功能对象,图中的意思是在Activity中使用对象进行业务操作,当然也不仅限于Activity。

    上图相对来说还是太简略了,并没有完整的表达出Dagger2的原理,下面我们直接从代码中感受一个Dagger2的强大。

    1.引入Dagger2

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

    2.创建网络访问对象及其Module模块

    首先创建一个HttpObject,我们假设这个HttpObject中有各种网络的操作,get,post,put等

    public void get(){
            Log.i("Dagger2","这里是get方法");
        }
        
        public void post(){
            Log.i("Dagger2","这里是post方法");
        }
    }
    创建HttpModule
    
    @Module
    public class HttpModule {
        @Provides
        public HttpObject providerHttpObject(){
            return new HttpObject();
        }
    }
    

    HttpModule的两个注解是需要注意的地方:@Module这个注解相当于给当前类打了一个标记,表明了这个类的类型,便于注入到容器中;@Provides这个注解放在了方法的上面,从上面的代码可以看出来,主要就是创建功能对象。

    3.创建容器Component

    @Component(modules = {HttpModule.class})
    public interface MyComponent {
        void injectMainActivity(MainActivity mainActivity);
    }
    

    容器这个类被@Component所注解,而且是一个接口类,@Component中的modules参数接收的类型是一个数组,表示被装入容器的Module有哪些。injectMainActivity方法表示这个容器中的功能对象(例如HttpObject)会在哪个类使用,我这里使用的MainActivity做的测试,所以参数写的是MainActivity。

    4.在类中使用HttpObject

    在配置完上述的代码之后,一定先rebuild!

    public class MainActivity extends AppCompatActivity {
        @Inject
        HttpObject mHttpObject;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMyComponent.create().injectMainActivity(this);
            mHttpObject.get();
            mHttpObject.post();
        }
    }
    

    因为我们要使用的类是HttpObject,所以在MainActivity创建这个类的对象,然后被@Inject所注解。要注意的是DaggerMyComponent这个类是rebuild之后生成的,调用DaggerMyComponent.create().inkectMainActivity(this)这句话来生成mHttpObject对象,调用HttpObject中的get和post方法就会有相应的输出。

    Dagger 2原理

    相比机械性的记住这些注解以及使用流程,Dagger 2 背后的工作原理更加重要,这样我们将明白各个模块的职责,以及框架是如何将它们关联起来帮助我们完成依赖注入的,明白了原理后使用 Dagger 2 就会更加得心应手了。

    所以我们这里先了解 Dagger 2 背后的基本原理,然后再学习其它内容。

    以前边的demo为例,项目编译后会在app\build\generated\source\apt\debug\包名目录下生成依赖注入的相关类,如下:

    按照之前说法,DaggerMainComponent是完成依赖注入的核心,所以从这个类开始分析,它的源码如下:

    public final class DaggerMainComponent implements MainComponent {
      private MainModule mainModule;
    
      private DaggerMainComponent(Builder builder) {
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
        this.mainModule = builder.mainModule;
      }
      // 重写inject方法,完成依赖注入
      @Override
      public void inject(MainActivity activity) {
        injectMainActivity(activity);
      }
      // 完成依赖注入的重要方法
      private MainActivity injectMainActivity(MainActivity instance) {
        // 给 MainActivity 中的 cat 成员变量赋值
        MainActivity_MembersInjector.injectCat(instance, new Cat());
        // 给 MainActivity 中的 flower 成员变量赋值
        MainActivity_MembersInjector.injectFlower1(
            instance, MainModule_ProvideRedRoseFactory.proxyProvideRedRose(mainModule));
        return instance;
      }
     
      public static final class Builder {
        private MainModule mainModule;
    
        private Builder() {}
        // 完成DaggerMainComponent对象的创建
        public MainComponent build() {
          if (mainModule == null) {
            this.mainModule = new MainModule();
          }
          return new DaggerMainComponent(this);
        }
        // 设置 mainModule 对象
        public Builder mainModule(MainModule mainModule) {
          this.mainModule = Preconditions.checkNotNull(mainModule);
          return this;
        }
      }
    }
    

    典型的 Builder 构建模式,再结合之前 DaggerMainComponent 的用法来分析:

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

    先通过builder()方法创建一个 Builder 对象,再通过其mainModule()方法设置mainModule 对象,接下来用 build()方法就是创建DaggerMainComponent 对象,这样它里边也有了一个mainModule对象。

    在 DaggerMainComponent 中还重写了 MainComponent 接口的inject()方法,里边调用的injectMainActivity()方法是完成依赖注入的关键:

    private MainActivity injectMainActivity(MainActivity instance) {
        MainActivity_MembersInjector.injectCat(instance, new Cat());
        MainActivity_MembersInjector.injectFlower1(
            instance, MainModule_ProvideRedRoseFactory.proxyProvideRedRose(mainModule));
        return instance;
      }
    

    首先是调用MainActivity_MembersInjector类的injectCat()方法直接创建一个 Cat 对象,完成 MainActivity 中 cat 的赋值,injectCat()方法声明如下:

    public static void injectCat(MainActivity instance, Cat cat) {
        instance.cat = cat;
      }
    

    然后是调用injectFlower()方法,完成 MainActivity 中 flower 的赋值,那么 flower 对象的值从哪里来呢?这里调用了MainModule_ProvideRedRoseFactory的proxyProvideRedRose()方法:

    public static Flower proxyProvideRedRose(MainModule instance) {
        return Preconditions.checkNotNull(
            instance.provideRedRose(), "Cannot return null from a non-@Nullable @Provides method");
      }
    

    里边最终是调用了我们在 MainModule 中声明的 provideRedRose() 方法,所以在 DaggerMainComponent 内部是通过 MainActivity_MembersInjector 完成了最终的依赖注入。所以当在 Activity 中执行inject(this)方法时,就是开始创建依赖对象,并完成注入工作。

    到这里整个依赖注入的流程就结束了,从源码的角度来看,整个过程更像是医生给患者注射药物。我们可以把依赖注入组件 DaggerMainComponent 看做“医生”,把 MainActivity_MembersInjector 看做“注射器”,MainModule 就是“药物”,MainActivity 就是“患者”,医生用注射器把药物送到患者体内。

    Dagger的优点

    有的小伙伴会问,你整这么一大堆是为了啥?要不然直接创建对象,要不然创建一个单例,多省事,可比Dagger2的这种方式方便多了。在中大型项目中,类似于HttpObject这种对象会被大量的应用,如果突然有一天这个类的初始化方法改变了,你岂不是要修改每一处吗。即便是使用单例getInstance方法也避免不了这种问题,因为如果在创建对象的时候需要在构造器中添加一个参数,每一处的getInstance也需要被修改。而Dagger2完美的避免了这种问题。


    以上就是Android中Dagger 2的基本使用以及原理的学习,有关Android开发中还有更多的学习技术;这里推荐参考《Android核心技术手册》这个大文档里面记录了30多个技术板块。几千个小知识点带你引进更高的技术层面。

    总结

    Dagger 2 的主要内容就这些了,使用 Dagger 2 必然要编写相关的辅助类、接口、使用各种注解,虽然没有直接 new 一个对象或者传统的依赖注入方式简单,但 Dagger 2 带来的是更好的代码解耦,更有利于后期的扩展维护,对于那些需要长期维护的项目这一点是更加重要的。

    相关文章

      网友评论

        本文标题:Android学习进阶——Dagger 2 使用及原理

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