记录Dagger2
昨天才开始接触dagger2这种依赖注入框架,瞎玩了一会完全搞不懂之中的工作原理和联系,今天算是有所突破,就此记录下。
依赖注入:就是目标类(目标类需要进行依赖初始化的类,下面都会用目标类一词来指代)中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建,而是通过技术手段可以把其他的类的已经初始化好的实例自动注入到目标类中。
开始的时候我有几个疑问:
1.Dagger2中Module,Component,Inject,Provides到底是个什么东西,什么意思?
2.他们之间在项目中扮演的是什么样的角色?
3.dagger2到底能带来什么样的好处?
之前
好不容易找到了一篇通俗易懂的文章,我就引入他的图片
就像想这就是依赖注入的概念
@Inject
Inject用注解(Annotation)来标注目标类中所依赖的其他类,同样用注解来标注所依赖的其他类的构造函数
这里有几点需要注意的细节,
1.目标类中被Inject标注的属性不能是private,否则会报错Dagger does not support injection into private fields
2.Inject注解标注的是目标类的属性和对应的构造函数,Inject不能标注同一个类的多个构造函数,否则会依赖迷失
3.运行时会优先从module中被@Provides注解标识的方法中寻到实例,没有相对应的方法就会去构造函数中寻找,
也就是说module的维度要大于Inject的维度。
这些不懂不着急,先往下看
Component
上图可以看出,被@Inject标识的属性和实例之间是没有连接的桥梁的,而Component就担任的是这个桥梁的角色。
Component是一个注解类,一个类想要是Component,必须要被@Component注解标识,而且这个类必须是抽象类或者接口
接下来看Component是怎么工作的
@Component(modules = MainMoudle.class) //@ProvideCompany public interface MainComponent { void inject(MainActivity mainActivity); }
Component需要目标类的实例,Component会查找目标类中用Inject注解标注的属性,查找到相应的属性后会接着查找该属性对应的用Inject标注的构造函数(这时候就发生联系了),剩下的工作就是初始化该属性的实例并把实例进行赋值。因此我们也可以给Component叫另外一个名字注入器(Injector)
Module
还有一个场景,加入我们的项目中引用了第三方库里面的类,但是这些类又不能随便修改,那之前说的@Inject就废了,根本就找不到实例化的对象。
//@Provides都必须包含在@Module内部,相当于简单工厂,提供了各种依赖@Provides方法 @Module public class MainMoudle { //Provids标注的方法就是提供对象的,一般会返回对象的实例 @Provides @ProvideCompany("") Company providesCompany() { Company company = new Company(); Log.d("Dagger2Test", company.toString()); return company; } }
Module其实是个简单工厂模式,里面的方法大都是创建类实例的方法
Component的新职责就是管理好Module,Component中的modules属性可以把Module加入Component,modules可以加入多个Module。
Provides
最终解决第三方库的依赖问题。
Module中创建实例的方法用@Provides进行标注,component在目标类中发现用@Inject标注的属性后就会子module中查找有@Provides的方法,这样就剋
Qualifier(限定符)
上面我们也说了,Component可以从两个地方获取实例化对象
[email protected]标注的构造方法中
2.module中标注@Provides的方法中
可是在实际的开发中,我们可能需要多个实例化对象,通过不同的构造函数来实例化得到不同的对象,要是按照之前的方法,会引起依赖注入迷失的问题
所以我们不能在同一个类中的多个构造函数中都标上@Inject。
这个时候@Qualifier的作用就体现出来了
@Qualifier //依赖迷失 @Retention(RetentionPolicy.RUNTIME)//元注解 运行时注解 /** * 用来防止依赖迷失,目标类中的属性用这种方式注解的表示只用module中相应privides提供的实例 */ public @interface ProvideCompany { String value() default ""; }
都说module类似于工厂模式了,在module中也是通过得到我们自定义的注解@Provides("value")来判断到底使用哪个Provides提供的方法来创建实例。
在module中
@Provides @ProvideCompany("good") Company providesGoodCompany(){ Company company = new Company(new Department(new Staff())); Log.d("Dagger2Test",company.toString()); return company; }
在目标类中
@Inject @ProvideCompany("good") Company company2;
Component这样就知道了应该使用哪个Provides啦
建议看下牛晓伟的写的文章,这是我找了很多,唯一一个让我觉的通俗易懂的