1、Dagger2是什么?
首先,我们要明白Dagger2是Android中比较热门的依赖注入框架。什么是依赖注入呢?
通俗来讲,依赖注入就是一个类中需要依赖其他对象时,不需要你亲自为那些需要依赖的对象赋值,为那些对象赋值的操作都交给了IOC框架
Dagger2介绍
一般的IOC框架都是通过反射实现的。但是Dagger2作为android的框架,为了不影响其性能,它是通过apt动态生成的代码
Dagger2主要分为三个部分
1、依赖提供方Module,负责提供依赖中所需要的对象,实际编码中类似于工厂类
2、依赖需求方实例,他在实际编码中对应业务Activity.当你在Activity中需要某个对象的时候,你只需要声明就行了
3、依赖注入的组件Component,负责将对象注入在依赖需求方里面,它在实际编码中是一个接口,编译Dagger2会自动为它生成一个实现类
Dagger2的主要工作流程
1、将依赖需求房(Activity里面声明)传入给Component的实现类
2、Component实现类会根据依赖需求方实例中依赖声明,来确定实例需要依赖哪些对象
3、确定依赖对象后,Component会在与自己关联的Module类中查找有没有提供这些依赖对象的方法,有的话就将Module类中提供的对象设置到依赖需求方实例中
2、实例
在项目下的build.gradle文件中添加apt插件:
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. |
在app目录的build.gradle文件中添加:
1 | //应用apt插件 |
编写布料类Cloth
写一个Cloth类用作依赖对象,它包含一个color属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Cloth {
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return color + "布料";
}
}
书写Module类
现在的需求是MainActivity中需要使用到Cloth对象,所以我们要为MainActivity书写一个Module类用来提供Cloth对象,相当于创建一个提供商
1 | @Module |
@Module:表面该类是Module类,Dagger2用来识别的
@Provides:声明Module类中,该方法是依赖对象的
在一个方法中声明@Provides注解,就相当于创建了一条生产线,这个生产线的产物就是该方法的返回值。有了这条生产线,
供应商就能提供这种类型的商品,当商店老板发现有人需要这种类型的商品时,供应商就可以提供给它了
书写Component接口
1 | @Component(modules=MainModule.class) |
和Module类一样,Component也需要注解声明的,那个注解就是@Component。
@Component注解的作用
@Component注解有两个属性,分别是modules和dependcies.这两个属性的类型都是Class数组
1、Modules :声明Component含有几个Moudle。当Component需要某个依赖的时候,就会通过这些Module类中对应的方法获取依赖对象。
MainComponent中只包含MainMoudle,所以令moudles=Maindule.class.这就相当于供应商和商店老板确定了合作关系
2、dependencies :声明Component类的依赖关系,这个下面在详细讲解
接口中的那个方法的作用
我们现在之声明了Component类,但是我们要怎么将Component类和依赖需求方对象联合起来呢。这个就是那个方法的作用。
这个方法可以将需求方的依赖对象传送到Component类中。Component类就会根据依赖需求方对象中声明的依赖关系来注入
依赖需求方对象中所有的对象
注意:
本demo中,MainActivity中需要Cloth对象,所以我们通过inject方法将Activity的实例传入到依赖组件MainComponent中,依赖组件MainComponent就会从提供方MainMoudle中的getCloth方法中获取cloth实例,并将该实例赋值给依赖需求方MainActivity中的cloth字段,相当于你去商店的道路,没有这条路,你就无法去商店和老板说明你需要的东西。但是这里需要注意的是,inject方法的参数不能用父类来接收,例如本Demo中,如果inject的参数是Activity,那么Dagger2就会报错
在MainActivity中声明
1 | public class MainActivity extends AppCompatActivity { |
上面代码有两处比较关键
1、声明依赖对象Cloth,就是在Cloth字段上添加@Inject注解,Dagger2中声明依赖对象都是通过@Inject注解的。
注意:@Inject注解字段不能是private和protected
2、通过dagger2自动生成的类来创建Component的实现类,创建时需要传入该ComPonent实现类所需要的Moudle类的实例。传入方法就是调用Moudle类类名首字母小写所对应的方法。这里我们通过Dagger2自动生成DaggerMainComponent类创建了。
MainComponent的实例,相当于我们创建了一个实实在在的商店,不在是理论上的商店,但是创建商店一定要创建真是的供应商,所以创建Component实现类时一定要传入Moudle实例.(注意编写完Component接口后Dagger2并不会自动创建对应的类,需要我们点击Android Studio中bulid菜单下的Rebulid Poject选项,或者直接书写代码,编译时Dagger2就会帮你自动生成).
再将MainActivity通过inject方法发送到MainComponent中,调用完inject方法后,你就会发现,MainActivity中的cloth字段已经被赋值,而且该cloth对应的就是我们在MainModule类的getCloth方法中创建的Cloth对象。
结果
另一种方法–构造函数声明@Inject,这样我们就不需要跟上面一样那么麻烦,又要写module类,又要写什么Component接口
创建依赖类 shope
1 | public class Shoe { |
这次我们创建的方式和Cloth不一样了,我们在构造方法上声明了@Inject注解。
这个注解的作用:当Component所拥有的Module类找不到依赖需求方需要类型的提供方法的时候,Dagger就会检查该需要类型有没有@Inject声明的构造方法,有的话就用该构造方法创建一个
(相当于你去商店购买东西,你需要的东西商店的供应商不生产,商店老板只好去网上看看有没有你需要的东西,有的话就帮你网购一个)
在MainActivity中声明Shope
1 | public class MainActivity extends AppCompatActivity { |
结果
注意
为什么不都用这种方法来声明呢,为什么要用Moudle类?
这是因为项目中,我们会用到别人的jar包,我们无法修改别人的源码,就更别说在别人的代码上添加注解了,所以我们只能通过Module类来提供
Shope是在源码的构造方法上面添加@Inject
而前面的代码是通过Module类引进进来的。
例如,我们创建的这些依赖类都不用依赖其他依赖类,但是如果需要依赖其他的依赖类又要怎么弄呢?
创建依赖类Clothes
我们又要创建一个衣服类Clothes,制作衣服时需要布料,所以我们在创建Clothes的实例时需要用到Cloth实例
1 | public class Clothes{ |
在Module类中增加提供方法
现在我们的MainActivity中需要依赖与Clothes对象,我们在MainActivity中添加提供Clothes对象的方法。但是Clothes需要依赖Cloth对象,这要怎么办呢?可能最先想到的办法是这样;
1 | @Provides |
直接在方法中创建了一个Cloth方法不就得了,但是你有没有发现,创建Cloth的方法已经在getCloth()方法中有了,我们能不能用getCloth方法中创建的Cloth实例来创建Cloth实例呢?
Dagger2提供了这样的一个功能,我们只要在getClothes方法中添加Cloth参数,Dagger2就会像帮依赖需求方找依赖对象一样帮你找到该方法依赖的Cloth实例,所以我们的代码可以这样写:
1
2
3
4@Provides
public Clothes getClothes(Cloth cloth){
return new Clothes(cloth);
}
在MainActivity中声明Clothes依赖
我们修改之前的MainActivity,添加一点东西
1 | public class MainActivity extends AppCompatActivity { |
结果
依赖总结
同理,在带有@Inject注解的构造函数要是依赖其他对象,Dagger2也会帮你自动注入
我们有两种方式可以提供依赖,一个是注解的@Inject的构造方法,一个是在Module里提供的依赖,那么Dagger2是怎么进行选择的呢?
步骤1、查找Module中是否存在创建该类的方法
步骤2、若存在创建该类的方法,查看该方法是否存在参数
步骤2.1、若存在参数,则按从步骤1开始依次初始化每个参数
步骤2.2、若不存在参数,则直接初始化该类的实例,一次依赖注入到此结束
步骤3、若不存在创建类的方法,则直接查找Inject注解的构造函数,看构造函数是否存在参数
步骤3.1、若存在参数,则从步骤1开始依次初始化每个参数
步骤3.2、若不存在参数,则直接初始化该类实例,一次依赖注入到此结束