首页 > 系统 > Android > 正文

Android 依赖注入框架 Dagger2使用

2019-11-07 22:51:56
字体:
来源:转载
供稿:网友

前言

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"; }}@Componentpublic 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);}@Modulepublic 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:查找Module中是否存在创建该类的方法。步骤2:若存在创建类方法,查看该方法是否存在参数 步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数 步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此-结束步骤3:若不存在创建类方法,则查找Inject注解的构造函数, 看构造函数是否存在参数 步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数 步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束

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

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

3. @Scope作用域

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

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

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

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从入门到放弃再到恍然大悟


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表