写点什么

Android—Dagger2- 让你爱不释手 -- 重点概念讲解、融合篇

用户头像
Android架构
关注
发布于: 刚刚

Android:dagger2让你爱不释手-基础依赖注入框架篇这篇讲解了 Inject,Component,Module,Provides 是如何构成 dagger2 整个依赖注入框架



因为 dagger2 的整个依赖注入框架已经构建完成,所以 dagger2 中剩下的 Qualifier(限定符)、Singleton(单例)、Scope(作用域),SubComponent 概念基本都是在对整个依赖注入框架进行细节上的完善。我还是依然从抽象概念的角度讲解,讲解每个概念在整个依赖注入框架中到底起了什么作用,因为 dagger2 本身不容易上手,只有真正的了解了每个概念的作用,在使用时才会得心应手,大家别急,后面的章节会有 dagger2 的 sample。

本节内容

  • Qualifier(限定符)、Singleton(单例)、Scope(作用域)、Component 的组织方式概念讲解

  • dagger2 能带来哪些实惠?在讲解时,我还依然沿用上一节的讲解方式,由简入难不断深入的进行。

Qualifier(限定符)是什么鬼?

上一节已经提到,Component 是一个注入器(Injector),同时也起着桥梁的作用,一端是创建类实例端(创建类实例即负责生产类实例,下面会用该词来指代),另一端是目标类端(目标类需要进行依赖初始化的类,下面都会用目标类一词来指代),请看下图:



创建类实例有 2 个维度可以创建:


  • 通过用 Inject 注解标注的构造函数来创建(以下简称 Inject 维度)

  • 通过工厂模式的 Module 来创建(以下简称 Module 维度)


这 2 个维度是有优先级之分的,Component 会首先从 Module 维度中查找类实例,若找到就用 Module 维度创建类实例,并停止查找 Inject 维度。否则才是从 Inject 维度查找类实例。所以创建类实例级别 Module 维度要高于 Inject 维度。


现在有个问题,**基于同一个维度条件下,若一个类的实例有多种方法可以创建出来,那注入器(Component)应该选择哪种方法来创建该类的实例呢?**如下图,基于 Inject 维度:



我把上面遇到的问题起个名字叫依赖注入迷失。那么可以给不同的创建类实例的方法用标识进行标注,用标识就可以对不同的创建类实例的方法进行区分(标识就如给不同的创建类实例方法起了一个 id 值)。同时用要使用的创建类实例方法的标识目标类相应的实例属性进行标注。那这样我们的问题就解决了,提到的标识就是 Qualifier 注解,当然这种注解得需要我们自定义。


Qualifier(限定符)就是解决依赖注入迷失问题的。注意 dagger2 在发现依赖注入迷失时在编译代码时会报错。

Scope(作用域)你真是挺坑的一个东东

我们暂且不介绍 Singleton,因为它是 Scope 的一个默认实现,理解了 Scope 自然就理解 Singleton 了。为什么要说 Scope 比较坑呢,在刚开始接触 Scope 的时候,看了网上各种关于 Scope 的介绍,总结 Scope 的作用是:


Dagger2 可以通过自定义 Scope 注解,来限定通过 Module 和 Inject 方式创建的类的实例的生命周期能够与目标类的生命周期相同。或者可以这样理解:通过自定义 Scope 注解可以更好的管理创建的类实例的生命周期。


网上也有各种例子比如:自定义一个 PerActivity 注解,那创建的类实例就与 Activity**“共生死“**。或者用 Singleton 注解标注一个创建类实例的方法,该创建类实例的方法就可以创建一个唯一的类实例。


我对 PerActivity 和 Singleton 这些魔法性的注解产生了好奇,同时也产生了迷惑?迷惑是:


  • 自定义 Scope 注解到底是怎么工作的

  • 自定义的注解应该怎么定义名字,是不是定义一个名字就可以达到相应名字的效果。比如 Singleton 就可以实现单例,PerActivity 就可以创建的类实例与 Activity**“共生死“,是不是我定义一个 PerFragment 的注解,同样可以达到创建的类实例就与 Fragment“共生死“**。大家别对我这幼稚的想法千万别见笑,当时我就把 dagger2 的 Scope 注解想的如此神通广大了


于是乎我在网上进行各种搜索,并且分析源码,最后的得到的结果也是让我大吃一惊。自定义的 Singleton、PerActivity 注解根本就没有这些功能。所以也可以说我被 Scope 坑了,或者是由于自己没有对 Scope 有一个深入的理解,被自己坑了。这先卖个关子,后面会具体介绍 Scope。

Component 组织方式重点中的重点

为什么说 Component 组织方式是重点中的重点呢?因为前面的各种概念都是在做铺垫工作,现在我们会从一个 app 的角度来把这些概念融合在一起。

一个 app 中应该根据什么来划分 Component?

假如一个 app(app 指的是 Android app)中只有一个 Component,那这个 Component 是很难维护、并且变化率


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


是很高,很庞大的,就是因为 Component 的职责太多了导致的。所以就有必要把这个庞大的 Component 进行划分,划分为粒度小的 Component。那划分的规则这样的:


  • 要有一个全局的 Component(可以叫 ApplicationComponent),负责管理整个 app 的全局类实例(全局类实例整个 app 都要用到的类的实例,这些类基本都是单例的,后面会用此词代替)

  • 每个页面对应一个 Component,比如一个 Activity 页面定义一个 Component,一个 Fragment 定义一个 Component。当然这不是必须的,有些页面之间的依赖的类是一样的,可以公用一个 Component。


第一个规则应该很好理解,具体说下第二个规则,为什么以页面为粒度来划分 Component?


  • 一个 app 是由很多个页面组成的,从组成 app 的角度来看一个页面就是一个完整的最小粒度了。

  • 一个页面的实现其实是要依赖各种类的,可以理解成一个页面把各种依赖的类组织起来共同实现一个大的功能,每个页面都组织着自己的需要依赖的类,一个页面就是一堆类的组织者。

  • 划分粒度不能太小了。假如使用 mvp 架构搭建 app,划分粒度是基于每个页面的 m、v、p 各自定义 Component 的,那 Component 的粒度就太小了,定义这么多的 Component,管理、维护就很非常困难


所以以页面划分 Component 在管理、维护上面相对来说更合理。

Singleton 没有创建单例的能力

为什么要谈到创建单例呢?因为上面谈到一个 app 要有一个全局的 Component(我们暂且叫 ApplicationComponent),ApplicationComponent 负责管理整个 app 用到的全局类实例,那不可否认的是这些全局类实例应该都是单例的,那我们怎么才能创建单例?


上一节提到过 Module 的作用,Module 和 Provides 是为解决第三方类库而生的,Module 是一个简单工厂模式,Module 可以包含创建类实例的方法


现在 Modlule 可以创建所以类的实例。同时


Component 会首先从 Module 维度中查找类实例,若找到就用 Module 维度创建类实例,并停止查找 Inject 维度。否则才是从 Inject 维度查找类实例。所以创建类实例级别 Module 维度要高于 Inject 维度。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android—Dagger2-让你爱不释手--重点概念讲解、融合篇