Dagger2入门

框架源码:https://github.com/google/dagger
Dagger 2 完全解析系列:
Dagger 2 完全解析(一),Dagger 2 的基本使用与原理
Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等
Dagger 2 完全解析(三),Component 的组织关系与 SubComponent
Dagger 2 完全解析(四),Android 中使用 Dagger 2
Dagger 2 完全解析(五),Kotlin 中使用 Dagger 2
Dagger 2 完全解析(六),dagger.android 扩展库的使用


Dagger 2 完全解析(一),Dagger 2 的基本使用与原理
https://www.jianshu.com/p/26d9f99ea3bb

  • 什么是依赖注入
    依赖注入(Dependency Injection,简称 DI)是用于实现控制反转(Inversion of Control,缩写为 IoC)最常见的方式之一,控制反转是面向对象编程中的一种设计原则,用以降低计算机代码之间耦合度。控制反转的基本思想是:借助“第三方”实现具有依赖关系的对象之间的解耦。一开始是对象 A 对 对象 B 有个依赖,对象 A 主动地创建 对象 B,对象 A 有主动控制权,实现了 Ioc 后,对象 A 依赖于 Ioc 容器,对象 A 被动地接受容器提供的对象 B 实例,由主动变为被动,因此称为控制反转。注意,控制反转不等同于依赖注入,控制反转还有一种实现方式叫“依赖查找”(Denpendency Lookup)。更多控制反转的信息请看控制反转的维基百科

依赖注入就是将对象实例传入到一个对象中去(Denpendency injection means giving an object its instance variables)。依赖注入是一种设计模式,降低了依赖和被依赖对象之间的耦合,方便扩展和单元测试。

  • 依赖注入的实现方式

  • Dagger 2 的基本使用

  1. 引入 Dagger 2
    查询版本号:https://search.maven.org/search?q=dagger
    implementation 'com.google.dagger:dagger:2.21'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.21'
    implementation 'com.google.dagger:dagger-android:2.21'
    implementation 'com.google.dagger:dagger-android-support:2.21'
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.21'

如何在gradle中定义变量(比如 版本号)并引用?

  1. 使用 @Inject 标注需要注入的依赖
    创建所依赖对象的实例
    @Inject可以标注成员变量及构造函数
    build 后可以在build/generated/source/apt目录下看到 Dagger 2 编译时生成的
  2. Component 桥梁
    @Component可以标注接口或抽象类,Component 桥梁可以完成依赖注入过程,其中最重要的是定义注入接口,调用注入接口就可以完成 Man 所需依赖的注入。
    build 后会生成带有Dagger前缀的实现该接口的类
    Component 就是连接依赖的对象实例和需要注入的实例属性之间的桥梁。Component 会查找目标类对应的成员属性注入类(即 MembersInjector<Man>),然后把依赖属性的工厂实例(即 Car_Factory.create())传给注入类,再使用 Component 一开始定义的接口就能完成依赖注入。
    注意,Component 中注入接口的参数必须为需要注入依赖的类型,不能是 Man 的父类或子类,注入接口返回值为 void,接口名可以任意。
    接下来只需要在 Man 中调用injectMan方法就能完成注入。
  3. Module
    使用@Inject标注构造函数来提供依赖的对象实例的方法,不是万能的,在以下几种场景中无法使用:
    * 接口没有构造函数
    * 第三方库的类不能被标注
    * 构造函数中的参数必须配置
    这时,就可以用@Provides标注的方法来提供依赖实例,方法的返回值就是依赖的对象实例,@Provides方法必须在Module中,Module 即用@Module标注的类。所以 Module 是提供依赖的对象实例的另一种方式。
    约定俗成的是@Provides方法一般以provide为前缀,Moudle 类以Module为后缀,一个 Module 类中可以有多个@Provides方法。
    接下来,需要把可以提供依赖实例的 Module 告诉 Component:
    CarModule_ProvideCarFactory 和之前的 Car_Factory 类似,都实现 Factory<Car> 接口。
    生成的 DaggerManComponent 和之前相比只改变了一个方法:
  4. 总结
    Dagger 2 最核心的三个部分
  1. 需要注入依赖的目标类,需要注入的实例属性由@Inject标注。
  2. 提供依赖对象实例的工厂,用@Inject标注构造函数或定义Module这两种方式都能提供依赖实例,Dagger 2 的注解处理器会在编译时生成相应的工厂类。Module的优先级比@Inject标注构造函数的高,意味着 Dagger 2 会先从 Module 寻找依赖实例。
  3. 把依赖实例工厂创建的实例注入到目标类中的 Component。
Dagger 2 最核心的三个部分

下面再讲述上面提到的在 Dagger 2 种几个注解的用法:

  • @Inject 一般情况下是标注成员属性和构造函数,标注的成员属性不能是private,Dagger 2 还支持方法注入,@Inject还可以标注方法
  • @Provides 只能标注方法,必须在 Module 中
  • @Module 用来标注 Module 类
  • @Component 只能标注接口或抽象类,声明的注入接口的参数类型必须和目标类一致。

完整代码:
https://github.com/WaterYuanData/AIDL/tree/master/teatdagger/src/main/java/com/yuan/teatdagger/dagger2
com.yuan.teatdagger.dagger2包下是@Inject构造函数注入
com.yuan.teatdagger.dagger2.module包下是@Module类@Provides方法注入


Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等

  • Lazy (延迟注入)
    有时我们想注入的依赖在使用时再完成初始化,加快加载速度,就可以使用注入Lazy<T>。只有在调用 Lazy<T> 的 get() 方法时才会初始化依赖实例注入依赖。
  • Provider 注入
    有时候不仅仅是注入单个实例,我们需要多个实例,这时可以使用注入Provider<T>,每次调用它的 get() 方法都会调用到 @Inject 构造函数创建新实例或者 Module 的 provide 方法返回实例。
  • Qualifier(限定符)的作用相当于起了个区分的别名。
    试想这样一种情况:沿用之前的 Man 和 Car 的例子,如果 CarModule 提供了两个生成 Car 实例的 provide 方法,Dagger 2 在注入 Car 实例到 Man 中时应该选择哪一个方法呢?
  1. 在 provide 方法上加上@Named注解,用来区分
  2. 还需要在 Inject 注入的地方加上@Named注解,表明需要注入的是哪一种 Car
  • Scope(作用域)

@Scope是元注解,是用来标注自定义注解的,MyScope 就是一个 Scope 注解

@Documented
@Retention(RUNTIME)
@Scope
public @interface MyScope {}

Scope 注解只能标注目标类、@provide 方法和 Component。Scope 注解要生效的话,需要同时标注在 Component 和提供依赖实例的 Module 或目标类上。Module 中 provide 方法中的 Scope 注解必须和 与之绑定的 Component 的 Scope 注解一样,否则作用域不同会导致编译时会报错。
Scope 作用域的本质:Component 间接持有依赖实例的引用,把实例的作用域与 Component 绑定,它们不是同年同月同日生,但是同年同月死。

  • Singleton Scope
    Singleton 作用域可以保证一个 Component 中的单例,但是如果产生多个 Component 实例,那么实例的单例就无法保证了。
    应用场景:AppComponent
    Component 可以同时被多个 Scope 标记
  • Reusable Scope
    只想单纯缓存依赖的实例,可以复用之前的实例,不想关心与之绑定是什么 Component
    Reusable 作用域只需要标记目标类或 provide 方法,不用标记 Component
  • Releasable references(可释放引用)
    使用 Scope 注解时,Component 会间接持有绑定的依赖实例的引用,也就是说实例在 Component 还存活时无法被回收。而在 Android 中,应该尽量减少内存占用,把没有使用的对象释放,这时可以用@CanReleaseReferences标记 Scope 注解。
    然后在 Application 中注入ReleasableReferenceManager对象,在内存不足时调用releaseStrongReferences()方法把 Component 间接持有的强引用变为弱引用。
  • Binding Instances
    Component 可以间接持有 Module 或 Inject 目标类构造函数提供的依赖实例,除了这两种方式,Component 还可以在创建 Component 的时候绑定依赖实例,用以注入。
  • 答疑
  1. 例如 Component 有 ScopeA 和 ScopeB 标记,那么它可以和 ScopeA 的 ModuleA、ScopeB 的 ModuleB 绑定。所以准确的说应该是,Module 的 Scope 必须包含在 Component 的 Scope 中
  2. 一般一个 Activity 只需要一个 Component,但是一个 Component 可以绑定多个 Module
  3. 在 @BindingInstance 例子中,定义的是 Builder activity(Activity activity); ,所以后面只能注入 Activity 类型。
    而之前 Module 构造函数绑定依赖实例中,参数为 HomeActivity,但是后面的 provide 方法返回的类型为 Activity,所以也只能提供 Activity 类型的依赖。
  4. 在activity中注入了一个presenter,这个presenter在哪里被销毁的
    4.1首先,presenter 被你注入到的 Activity 引用了,所以在 activity 未被销毁前是不会被回收的
    4.2 如果你使用了 Scope 作用域的话,管理 presenter 的 Component 还会间接保留一份 presenter 的引用,所以 presenter 的生命周期还和 Component 绑定,如果 component 实例被 activity 保留的话,那么 component 和 presenter 的生命周期都和 activity 一样了。
    4.3 但是如果使用的 AppComponent 注入的话,AppComponent 被 application 保留实例,那么 presenter 的生命周期就会和 application 绑定了。

一个整合了大量主流开源项目高度可配置化的 Android MVP 快速集成框架
https://github.com/JessYanCoding/MVPArms/blob/master/MVPArms.md

Dagger2神器入门(一)
https://www.jianshu.com/p/dce5382fec5d

Dagger2从入门到放弃再到恍然大悟
https://www.jianshu.com/p/39d1df6c877d

Android_Dagger2篇——从小白最易上手的角度 + 最新dagger.android
https://www.jianshu.com/p/22c397354997

Dragger2快速入门浅析
https://blog.csdn.net/Jet_Green/article/details/80996657

深入浅出Dagger2 : 从入门到爱不释手
https://www.jianshu.com/p/626b2087e2b1

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 一、首先你要知道什么是依赖? 想要理解Dagger2,首先你要理解一个概念,就是什么是依赖,懂的同学可以省过此段。...
    为梦想战斗阅读 436评论 0 0
  • 原文地址Dagger2 入门,以初学者角度 依赖注入 Dagger2是Android中比较热门的依赖注入框架,什么...
    Marlon_IT阅读 1,272评论 1 16
  • 1.Dagger2简介 1.1 Dagger2的描述 Github地址:Dagger2 Dagger2官网上介绍是...
    橙子只涩不酸阅读 786评论 0 1
  • Dagger2入门详解 参考文章 Dagger官网 Dagger Document API 从零开始的Androi...
    DakerYi阅读 1,190评论 0 7
  • Dagger2入门详解 @(Android) Dagger2入门详解 参考文章 环境配置 入门实例 其他注解和情况...
    JFang阅读 592评论 1 0