Dagger2
介绍Dagger2
1.基础知识点
- 依赖注入(Dependency Injection)
- Java的注解 (Annotation)
1.1 依赖注入 DI
目标类(需要进行依赖初始化的类)中所依赖的其他类的初始化过程,不是通过手动编码方式创建的类,通过技术手段,把其他类已经初始化好的实例自动注入到目标类中。
1.2 注解 Annotation
它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。
Annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。
2.Dagger2注解
2.1 @Inject
Inject主要有两个作用,一个是使用在构造函数上,通过标记构造函数让Dagger2来使用(Dagger2通过Inject标记可以在需要这个类实例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖,另一个作用就是标记在需要依赖的变量让Dagger2为其提供依赖。
2.2 @Provider
用Provide来标注一个方法,该方法可以在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Inject的变量赋值。provide主要用于标注Module里的方法
2.3 @Module
用Module标注的类是专门用来提供依赖的。有的人可能有些疑惑,看了上面的@Inject,需要在构造函数上标记才能提供依赖,那么如果我们需要提供的类构造函数无法修改怎么办,比如一些jar包里的类,我们无法修改源码。这时候就需要使用Module了。Module可以给不能修改源码的类提供依赖,当然,能用Inject标注的通过Module也可以提供依赖。
2.4 @Component
Component一般用来标注接口,Component也叫组件,方法中有dependenies,跟modules两个参数,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需要依赖方之间的桥梁,把相关依赖注入到其中。
2.5 提供依赖的流程
提供依赖有两种方式:
- 1.注解了@Inject的构造函数
- 2.注解了@Module 类中的@Provider 的方法
所以在依赖的选择上就有一个流程。
Dagger2选择依赖的流程:
- 步骤1:查找Module中是否存在创建该类的方法。
- 步骤2:若存在创建类方法,查看该方法是否存在参数
- 步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
- 步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
- 步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数
- 步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
- 步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
3. 两个比较难理解的注解:@Scope @Qulifiter
3.1 @Qulifiter
依赖迷失:如果有Module中有两个一样的返回类型,该用谁呢。我们把这种场景叫做依赖迷失。
@Qulifiter:通过自定义Qulifier,可以告诉Dagger2去需找具体的依赖提供者。
3.2 @Qulifiter使用
1.创建自定义注解:
|
|
通过@Qulifiter创建了两个自定义注解,@A 与 @B
2.在Module中使用@A 与 @B:
|
|
3.具体使用:
|
|
4.调用CookerA与CookerB
|
|
3.3 @Scope
Scope难理解,通过例子来解释:
####1.定义一个Scope
2.把定义的PerActivity放到Module
|
|
3.这个Module提供了CoffeeShop,CookerFactory和CookerFacotryMulty的依赖
CoffShop.java
CookerFactory.java
CookerFactoryMulty.java
我们在这三个对象的构造方法里都加了Log,当他们的实例产生时能看到相关的Log,再看我们用到的地方,在MainActivity里给每个类都写两个变量.
4.MainActivity中:
MainActivity.java
5.运行结果
|
|
从Log中可以看到,CoffeeShop和CookerFactory的类都只new过一次,而CookerFactoryMulty被new了两次 再回头看我们的Module,其中CoffeeShop的依赖是通过单例模式提供的,只打一条Log很容易理解,而CookerFactory相对于CookerFactoryMulty来说内容几乎是一模一样,只多加一个@PerActivity的注解,但却比它少打了一次Log,这是为什么呢。哈哈,客官们,这就是@Scope神秘的地方,他通过自定义@Scope注解提供了单例,正如上面的CookerFactory,虽然并未用单例来提供依赖,但却和用单例提供依赖的CoffeeShop一样,两个对象的实例都是同一个,这就是Scope的作用,提供局部单例的功能,局部范围是啥,那就是它生命周期范围内。
4.学习过程中遇到的一些坑
4.1 代码:
1.AppModule.java
|
|
2.UserModule.java
|
|
3.RepositoryComponent.java
|
|
4.ActivityComponent.java
|
|
4.2 上面代码解释:
1.AppModule
与UserModule
(UserModule.java是一个例子类,无实际作用)组成一个RepositoryComponent
的组件,组件内的Provider可以互相提供依赖,注入实例到同一个组件需要的依赖里面。
2.ActivityComponent
是提供给Activity类的组件,这个组件dependencies 依赖了RepositoryComponent
组件,然后加入了ActivityModule
。
3.重点:RepositoryComponent
放出了两个方法User getUser();
与@ForApplication MyApplication getApplication()
,在我看来,这两个方法相当于开放出两个接口,给依赖这个RepositoryComponent
组件的下层组件(这里是ActivityComponent
)来提供依赖。 例如, ActivityComponent
组件里面需要依赖一个RepositoryComponent
中的User,那么RepositoryComponent
中就需要定义这个User getUser()
方法。
如果需要开放的依赖有自定义的@Qulifiter
注解,那么在开放这个依赖的时候,也要对应加上这个注解,例如@ForApplication MyApplication getAplication()
, 对应的在下层依赖需要注入的时候也要带上这个@ForApplication
注解。