概述

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开发中还有更多的学习技术;这儿推荐参阅传送直达↓↓↓ :www.6hu.cc/go//?target=htt…这个大文档里面记录了30多个技术板块。几千个小知识点带你引入更高的技术层面。

总结

Dagger 2 的首要内容就这些了,运用 Dagger 2 必然要编写相关的辅助类、接口、运用各种注解,虽然没有直接 new 一个目标或许传统的依靠注入方式简略,但 Dagger 2 带来的是更好的代码解耦,更有利于后期的扩展保护,关于那些需求长时间保护的项目这一点是愈加重要的。