阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680
一、概述
Dagger2
依赖注入框架的好处:
- 依赖的注入和配置独立于组件之外
- 依赖对象是在一个独立、不耦合的地方初始化,当初始化方式改变的时候修改的代码少。
- 依赖注入使得单元测试更加简单。
Dagger2
相对于其它框架的优点:
- 编译期生成代码,有错误会在编译期报出。
- 错误可追踪。
- 易于调试。
Dagger2
的缺点:
- 缺少灵活性。
- 没有动态机制。
二、Dagger2
的注解
Dagger2
的注解主要有以下七类:
@Inject
:这个注解有两个作用:在目标类中标记成员变量告诉Dagger
这个类型的变量需要一个实例对象;标记依赖类中的构造方法,告诉Dagger
我可以提供这种类型的依赖实例。@Component
:用来标记接口或者抽象类,也被称为注入器,是@Inject
和@Module
的桥梁,所有的Component
都可以通过它的modules
知道它所提供的依赖范围,一个Componet
可以依赖一个或多个Component
,并拿到被依赖Component
暴露出来的实例,Componenet
的dependencies
属性就是确定依赖关系的实现。@Module
:用来标记类,一般类名以Module
结尾,Module
的主要作用是用来集中管理@Provides
标记的方法,我们定义一个被@Module
注解的类,Dagger
就会知道在哪里找到依赖来满足创建类的实例,Module
的一个重要特征是被设计成区块并可以组合在一起。@Provides
:对方法进行注解,并且这些方法都是有返回类型的,告诉Dagger
我们向如何创建并提供该类型的依赖实例(一般会在方法中new
出实例),用@Provides
标记的方法,推荐用provide
作为前缀。@Qualifier
:限定符,当一个类的类型不足以标示一个依赖的时候,我们就可以用这个注解,它会调用DataModule
中方法来返回合适的依赖类实例。@Scope
:通过自定义注解来限定作用域,所有的对象都不再需要知道怎么管理它的实例,Dagger2
中有一个默认的作用域注解@Singleton
,通常用来标记在App
整个生命周期内存活的实例,也可以定义一个@PerActivity
注解,用来表明生命周期要与Activity
一致。@SubComponent
:如果我们需要父组件全部的提供对象,我们就可以用包含方式,而不是用依赖方式,包含方式不需要父组件显示显露对象,就可以拿到父组件全部对象,且SubComponent
只需要在父Component
接扣中声明就可以了。
三、Dagger2
的简单应用 - @Inject
和@Component
第一步:基础配置,在build.gradle
中添加相应的依赖:
第二步:User
作为目标类中需要实例化的成员对象,给其构造函数添加@Inject
标签:
第三步:声明Component
:
第四步:在目标类中添加注解@Inject
,并根据我们第3步中声明的Component
,调用DaggerXXX
方法来进行注入:
上面这个例子有两个缺点:
- 只能标记一个构造方法,因为如果标记两个以上,不知道要用哪一个构造提供实例。
- 不能标记其它我们不能修改的类,例如第三方库。
- 如果用
@Inject
标记的构造函数如果有参数,那么这个参数也需要其它地方提供依赖,而类似于String
这些我们不能修改的类,只能用@Module
中的@Provides
来提供实例了。
四、采用@Module
来提供依赖
采用@Module
标记的类提供依赖是常规套路,@Module
标记的类起管理作用,真正提供依赖实例靠的是@Provides
标记的带返回类型的方法。
第一步:和上面类似,我们定义一个依赖类,但是它的构造方法并不需要用@Inject
标记:
第二步:我们需要定义一个@Module
来管理这些依赖类的实例:
第三步:定义一个@Component
,它指向上面定义的@Module
第四步:在目标类中进行依赖注入
这里注入的方式有两种,一种是像上面这样的,它适合于PersonDataModule
中只有一个无参的构造方法,否则我们需要这样调用:
五、初始化依赖实例的步骤
-
查找
Module
中是否存在创建该类型的方法(即@Component
标记的接口中包含了@Module
标记的Module
类,如果没有则直接查找@Inject
对应的构造方法)。 -
如果存在创建类方法,则查看该方法是否有参数
-
如果不存在参数,直接初始化该类的实例,一次依赖注入到此结束。
-
如果存在参数,则从步骤1开始初始化每个参数。
-
如果不存在创建类方法,则查找该类型的类中有
@Inject
标记的构造方法,查看构造方法是否有参数: -
如果不存在参数,则直接初始化该类实例,一次依赖注入到此结束。
-
如果存在参数,则从步骤1开始初始化每个参数。
六、@Qualifier
限定符
在Dagger
中,有一个已经定义好的限定符,@Name
,下面我们也自己定义一个限定符:
第一步:和前面类似,我们先定义一个需要实例化的依赖类:
第二步:我定义一个DataModule
,和前面不同的是,在它的provideXXX
方法的注解中,我们添加了@Name(xxx)
和自定义的注解PeopleThreePeople
:
第三步:定义Component
第四步:在目标类中进行依赖注入,在提供@Inject
注解时,我们还需要声明和PeopleDataModule
中对应的限定符,这样Dagger
就知道该用那个函数来生成目标类中的依赖类实例:
七、@Scope
@Scope
的作用主要是在组织Component
和Module
的时候起到一个提醒和管理的作用,在Dagger
中,有一个默认的作用域@Singleton
。@Scope
的作用是:Dagger2
可以通过自定义Scope
注解,来限定通过Module
和Inject
方式创建的类的实例的生命周期能够与目标类的生命周期相同。Scope
的真正作用在与Component
的组织:
- 更好的管理
Component
之间的组织方式,不管是依赖方式还是包含方式,都有必要用自定的Scope
注解标注这些Component
,而且编译器会检查有依赖关系或包含关系的Component
,若发现有Component
没有用自定义Scope
注解,则会报错。 - 更好地管理
Component
与Module
之间地关系,编译器会检查Component
管理的Module
,若发现Component
的自定义Scope
注解与Module
中的标注创建类实例方法的注解不一样,就会报错。 - 提高程序的可读性。
下面是一个使用@Singleton
的例子:
第一步:定义需要实例化的类:
第二步:定义DataModule
,在它的provideXXX
方法,提供了@Singletion
注解:
第三步:定义Component
,和前面不同的是,需要给这个Component
添加@Singleton
注解:
第四步:在目标类中进行依赖注入,每次启动Activity
的时候,我们可以发现打印出来的hash
值都是相同的:
八、组织Component
Component
有三种组织方式:
- 依赖:一个
Component
依赖一个或多个Component
,采用的是@Component
的dependencies
属性。 - 包含:这里就用到了
@SubComponent
注解,用它来标记接口或者抽象类,表示它可以被包干。一个Component
可以包含一个或多个Component
,而且被包含的Component
还可以继续包含其它的Component
。 - 继承:用一个
Component
继承另外一个Component
。
九、Google
官方框架分析
下面是Google
官方框架的目录结构:
可以看出,它把每个界面都作为一个独立的包(addedittask、statistics、taskdetail、tasks
),而数据、依赖类是其它的两个包(data、util
),我们先从ToDoApplication
开始分析:
在ToDoApplication
中,我们实例化了一个变量TasksRepositoryComponent
,它相当于是项目中所有其它Component
的管理者,它被声明为@Singleton
的,即在App
的生命周期中只存在一个,同时用@Component
表明它和TaskRepositoyModule
、ApplicationModule
这两个Module
关联。
TaskRpositotyModule
提供了两种类型的数据源对象,它们是用@Local
、@Remote
来区分的:
接下来再看一下ApplicationModule
下面我们用一个比较简单的界面来看一下TasksRepositoryComponent
是怎么和其它的Component
关联起来的,首先看StatisticsActivity
:
原文链接:https://www.jianshu.com/p/5285f48b6336
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680