前言

Dagger 2这个匕首确实很难上手,上手后又比较难瞬间掌握,可以这么说,刚开始使用就是用来尝(zhuang)鲜(X)的,但相信随着使用的加深,会不断体会到它对于整个项目架构的极强辅助作用,能使整个项目变得更清晰。它毕竟是一个依赖注入DI框架,Spring在服务器开发中起到的作用相信它也能。在了解使用前,先了解概念,什么是控制反转,什么是依赖注入。

1. 控制反转、依赖注入概念

**控制反转(Inversion of Control)**是一种思想,是面向对象编程中的一种设计原则,用来降低代码之间的耦合度。
**依赖注入(Dependency Injection)**是一种设计模式,就是将实例变量传入到一个对象中去。
它们的准则:对象构建和使用分离。

我们所使用的DI框架关心怎么样去把依赖和消费依赖者联系在一起(怎么在对象被需要时分配给它们)。即通过IoC框架,类A依赖类B的强耦合关系可以在运行时通过容器建立,也就是说把创建B实例的工作移交给容器,类A只管使用就可以。

关于理解依赖注入,可参考 依赖注入 理解Dependency Injection。

想想看,Dagger2 就仅仅通过几个注解,表明哪些提供依赖,哪些需要被注入,再通过Component搭建个桥梁连接它们,就很轻松的分离了创建和使用,在创建变化时也不用修改注入的代码,这就是依赖注入框架的方便之处。那么如何创建这些关系,怎么写代码。

2. Dagger2 用法

2.1. 在build.gradle中添加依赖

//项目gradle下添加
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'//app gradle下添加
apply plugin: 'android-apt' dependencies {compile 'com.google.dagger:dagger:2.4'apt 'com.google.dagger:dagger-compiler:2.4'compile 'org.glassfish:javax.annotation:10.0-b28' //javax注解
}

Dagger2 有两种注入方式

  • 使用 Inject维度 注入
  • 使用 Module维度 注入

接下来分别举出示例代码。

2.2 Inject维度

public class Apple {    public String name;    //要注入的类@Inject public Apple() {       this.name = "initApple";    }
}@Component
public interface LittleSampleComponent {   void inject(LittleSingleSampleFragment littleSingleSampleFragment);
}//在Activity中注入
@Inject Apple apple; //注入,使用@Inject表示这个变量需要被注入
@Override public void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);    DaggerLittleSampleComponent.builder().build().inject(this);//注入,连接关系LogUtil.d(apple.toString());
}

2.3 Module维度

@Component( modules = FruitModule.class)
public interface FruitComponent { void inject(FruitFragment fruitFragment);
}@Module
public class FruitModule {@Provides Fruit provideFruitA() {return new Fruit("redA", "bigA"); }
}//目标类中
@Inject Fruit fruit;
//如果module是空参构造函数可以不用.module(xxx)
DaggerFruitComponent.builder().build().inject(this);
LogUtil.d(fruit.toString());

这是两种最基本的用法,用到了几个基础注解。

  • @Inject
    **声明依赖。**主要是用来标注目标类的依赖和依赖的构造函数。标注目标类中所依赖的类,同样用来标注所依赖类的构造函数,只能给一个构造函数添加注解。
    @Inject可以标记目标类中的成员变量,但是这些成员变量要求是包级可见,即不可以标记private类型的成员变量。

  • @Module
    Module其实就是一个依赖的制造工厂,只需要在里面提供依赖就可。一个完整的Module必须拥有@Module与@Provides注解。
    module的作用是提供在应用的生命周期中存活的对象。

  • @Component
    连接依赖和消费依赖 。Component就是一个将Module中的依赖注入到目标类中的注入器。它需要引用到目标类的实例,然后会查找目标类中用Inject注解标注的属性,查找到相应的属性后会接着查找该属性对应的用Inject标注的构造函数(这时候就发生联系了),剩下的工作就是初始化该属性的实例并把实例进行赋值。
    在创建Component时,如果所依赖的Module只有有参构造函数,则必须要显示传入Module实例对象。如果空参,那么可以不传。

  • @Provides
    把Module中的各种创建类的实例方法与目标类中的用Inject注解标注的依赖产生关联。
    Module中的创建类实例方法用Provides进行标注,Component在搜索到目标类中用Inject注解标注的属性后,Component就会去Module中去查找用Provides标注的对应的创建类实例方法,这样就可以解决第三方类库用dagger2实现依赖注入了。
    @Provides方法可以带输入参数,其参数由Module集合中的其他@Provides方法提供。

其中,dagger2进行的一次依赖注入的步骤:

  1. 步骤1:查找Module中是否存在创建该类的方法。
  2. 步骤2:若存在创建类方法,查看该方法是否存在参数
  • 步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
  • 步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此-结束
  1. 步骤3:若不存在创建类方法,则查找Inject注解的构造函数, 看构造函数是否存在参数
  • 步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
  • 步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束

这个步骤很重要,很多使用地方不明白的看一遍这个查找顺序就明白了。

这就是Dagger2的基本使用。接下来介绍Dagger2中最难理解的地方,Scope。依赖迷失的注解@Qualifier请查看文末连接里的介绍,很好理解。

3. @Scope作用域

  1. Scope作用域依赖于Component生命周期
    @Scope是作用域注解,Dagger2里面提供了一个@Singleton注解,用以表明该对象是单例的。但是如何起作用的呢。
    首先,@Singleton注解的对象是保存在Component实例中的。并不是static final的被全局共享,而是该依赖对象的生命周期和其所在的Component的声明周期一样长。
    比如当我们使用ApplicationComponent时,很明显该Component的生命周期是整个应用,所有此时就可以创建一些全局单例依赖,比如网络retrofit等。又比如我们的Component是Activity的,我们就可以使用@PerActivity来修饰。
    所以,**Scope的实现归结于对Components的一个正确的设置。**Component的声明周期有多长,那么所提供的依赖生命周期就有多长。

  2. Scope增强可读性
    Scope增强可读性和方便理解,通过scope的不同很容易能辨明2个实例的作用域的区别。

  3. Scope的限制不同层级Component需要不同Scope
    Scope起的更多是一个限制作用,比如不同层级的Component需要有不同的scope,注入PerActivity scope的component后activity就不能通过@Inject去获得SingleTon的实例,需要从application去暴露接口获得(getAppliationComponent获得component实例然后访问,比如全局的navigator)。

  4. Scope用于组织Component
    正是因为Scope的限制,所有它可以被用来组织Component。
    一般情况下我们有两种方式组织Component :使用@Subcomponent注解或者使用Component dependencies。它们两者最大的区别就是对象图表的共享。Subcomponents可以访问它们parent的所有对象图表,而Component依赖只能访问通过Component接口暴露的对象。
    子Component的生命周期必须小于父Component,第二点说的不同层级的Component有不同的Scope。这点很重要,正是基于这种层级关系我们就可以从更高的角度来搭建整个项目的依赖、整个项目的层级。

结语

本篇文章从基础的注入方式直接跳到Scope用于组织项目层次,着实是因为Dagger2真的不是那么简单。不仅仅是用来在MVP中把Presenter注入到View中那么简单(真是大材小用)。这样你可以理解开头说的刚开始用就是用来装X,但熟悉了后就觉得是神器那句话了吧。

不多说了,学Dagger2难找的就是资料,下面贴出参考资料,多多实践。关于本文的代码在GitHub上 Dagger2Learn,全是一些小sample。

参考:

  • 看完就懂:
    Android常用开源工具(1)-Dagger2入门
    Android常用开源工具(2)-Dagger2进阶
    Android:dagger2让你爱不释手-基础依赖注入框架篇
    Android:dagger2让你爱不释手-重点概念讲解、融合篇
    Android:dagger2让你爱不释手-终结篇
  • 控制反转和依赖注入
    控制反转(IoC)与依赖注入(DI)
  • Scope
    Dagger2 Scope 注解能保证依赖在 component 生命周期内的单例性吗?
    使用Dagger 2依赖注入 - 自定义Scope
  • Dagger2用于组织项目
    从零开始的Android新项目4 - Dagger2篇
  • Dagger源码解析
    Dagger 源码解析
  • 好文
    Dagger2从入门到放弃再到恍然大悟

Android 依赖注入框架 Dagger2使用相关推荐

  1. 依赖注入框架Dagger2详解(一),依赖注入和控制反转的深入理解

    IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序,而Dagger2框架是依赖注入思想践行者的优秀代表. 依赖注入框架Dagger2详解(一), ...

  2. 深入浅出依赖注入框架Dagger2

    目录 目录 依赖注入 依赖注入实现的三种方式 1. 构造注入 2. 属性注入 3. 接口注入 Dagger2 Dagger2的引入 不带Module的Inject方式(Inject+Component ...

  3. Android 依赖注入 DI - Dagger2

    1.依赖注入 (Dependency Injection) 1.1 面向接口编程 public interface Drivable {void drive(); }public class Bike ...

  4. Android神匕首—Dagger2依赖注入框架详解

    简介 Dagger-匕首,鼎鼎大名的Square公司旗下又一把利刃(没错!还有一把黄油刀,唤作ButterKnife) Dagger2 是一个Android依赖注入框架,由谷歌开发,最早的版本Dagg ...

  5. Android:dagger2让你爱不释手-基础依赖注入框架篇

    前言 dagger2的大名我想大家都已经很熟了,它是解决Android或java中依赖注入的一个类库(DI类库).当我看到一些开源的项目在使用dagger2时,我也有种匆匆欲动的感觉,因此就立马想一探 ...

  6. android dagger2 懒加载,Android Dagger依赖注入框架浅析

    今天接触了Dagger这套android的依赖注入框架(DI框架),感觉跟Spring 的IOC差不多吧.这个框架它的好处是它没有采用反射技术(Spring是用反射的),而是用预编译技术,因为基于反射 ...

  7. dagger2 android快速注入框架相关学习资料

    2019独角兽企业重金招聘Python工程师标准>>> Android:dagger2让你爱不释手-基础依赖注入框架篇 地址:http://www.jianshu.com/p/cd2 ...

  8. android组件浮动在activity上_Jetpack Hilt 依赖注入框架上手指南

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:LvKang-insist 链接:https://juejin.im/post/5efdff9d6fb9a07e ...

  9. Kotlin替换Dagger2/Hilt的依赖注入框架--Koin。

    Koin.Dagger2.Hilt 目前都是非常流行的库,面对这么多层出不穷的新技术,我们该做如何选择,是一直困扰我们的一个问题. Hilt 与 Dagger2 区别并不大,Hilt就是对Dagger ...

最新文章

  1. python3 转码的函数_python基础3之文件操作、字符编码解码、函数介绍
  2. DevExpress.GridControl.gridView的一些注意
  3. java快速排序泛型,如何进行对C# .NET通用泛型进行快速排序?
  4. 人口问题,怎样的生育率才能保持正常的世代更替?
  5. 查看数据库系统字符集
  6. 用C#+Selenium+ChromeDriver 爬取网页,完美模拟真实的用户浏览行为
  7. Android Glide图片加载框架(二)源码解析之into()
  8. 揭秘Python并发编程——协程
  9. 【转】Android android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)...
  10. 剑指offer(C++)-JZ22:链表中倒数最后k个结点(数据结构-链表)
  11. Bert模型进行文本分类
  12. Anaconda下载官网
  13. AD19快速制作多管脚元件符号
  14. Unity FPS 计算
  15. 内外网隔离--网络准入控制系统有什么功能
  16. 二叉树的左视图-java
  17. 中国人误传千年的七句话
  18. QorIQ LX2160A安全引擎操作模式
  19. TCP协议的三次握手大体流程
  20. SDRAM学习(一)——初始化

热门文章

  1. itext7中文开发文档(三)
  2. SpringBoot+POI+JXL实现excel导出并添加水印功能
  3. 初学者必读VRay 2.0光源设置(4)——使用穹顶光源
  4. java thumbnails 内存_Java修改图片尺寸,总是报内存溢出怎么解决?
  5. 2018 上海国际服务机器人技术及应用展览会
  6. Unity UI适配不同比例分辨率的设置
  7. 高人气直播间必备的8个直播留人技巧
  8. 从程序员到项目经理:如何管理自己的时间
  9. Dell XPS 9360 安装debian10---安装后
  10. python 实现 画图器_按钮实现Python--绘图工具matplotlib的使用