首先,真实的原理我不准,但是我还是提供我的理解。
阅读这篇文章希望读者能满足一个假设:不管懂不懂,看过一些其他关于dagger2的文章(因为没图、没代码,不便于直观理解)。
在别人的文章里,会说“依赖”,“注入”,这当然是专业的说法,但是会让像我这样的新手搞的晕头转向。所以接下来我会用自己喜欢的词来描述,熟悉“依赖”、“注入”概念的请自行比对。
Dagger这个词的意思是“匕首”,匕首是用来扎的,不是砍;起名肯定是有用意的,也许就是“轻盈附着”的意思,本着“轻盈附着”的概念,于是我有了自己的类比。
因为dagger2 据说是有生命周期而且和对应View同等周期,所以我将dagger2的一系列理解为一个良性的寄生包群(不是肿瘤),寄主死的时候对应寄生包也就死了。
Dagger2 有几个比较主要的标记(正规叫法似乎是:注解)。
@Module 加在一个普通类头上,这个类就成了一个提供对象的载体,好比一只提供病毒的蚊子,当然了它是允许携带多种病毒的。它的主要作用是:灵活提供对象的一个类,或者说把需要提供的对象独立出来,进行配置。
@Module //@module声明这个类是携带实体的组件,一个“容器”
public class BehaviourModule {
}
@Provides (不好意思,我就是病毒)标记在提供对象的方法上。凡是被这个东西标记的方法,它的方法名已经不重要了(不是没有意义),将来对病毒的识别会通过对象类型,而不是通过方法名。注意,通过类型不是通过方法名!!所以类型是重点,如果类型重复,这里还有一个@Named的标签,就是在类型相同时用作区别标识;
@Module //@module声明这个类是携带实体的组件,一个“容器”
public class BehaviourModule {
@Named("A") //相同返回值类型时的区别符号
@Provides //@provides声明以下的类型将被提供出去
public Animal getAnimal(){
return new Tiger();
}
@Provides //同上
public Food getFood(){
return new Meat();
}
}
DaggerXXXComponent 按理说我应该先提到XXXComponent的。因为在代码顺序上是先有XXXcomponent这个接口,然后build工程才出现这个类。我依旧觉得它逻辑在先。这个类就是针对某个Activity或者Fragment的“小寄生包”,它将包含所有在其范围内的“病毒(@provides标记的对象)”,并提供Provider<T>的对象类型,它才是那个具有生命周期的东西。
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerBehaviourComponent implements BehaviourComponent {
private Provider<Animal> getAnimalProvider;//@Provides在这里成为了Provider<T>对象
private Provider<Food> getFoodProvider;//在initialize()会发现跟方法名没有半毛钱关系,只跟返回方法类型有关
private MembersInjector<Behaviour1Activity> behaviour1ActivityMembersInjector;//伴随生命周期对象
private DaggerBehaviourComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private void initialize(final Builder builder) {
//没有被@Inject标记使用的对象将不会在这里初始化,略智能
this.getAnimalProvider = BehaviourModule_GetAnimalFactory.create(builder.behaviourModule);
this.getFoodProvider = BehaviourModule_GetFoodFactory.create(builder.behaviourModule);
this.behaviour1ActivityMembersInjector = Behaviour1Activity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), getAnimalProvider, getFoodProvider);
}
@Override
public void inject(Behaviour1Activity activity) {
behaviour1ActivityMembersInjector.injectMembers(activity);
}
@Component 定义寄生包的接口,它必须是一个接口。标记后面的括号里会指定一个或者多个Module.class,表示它实现时要囊括的虫子。这个接口只要干了两件事:一、将“虫子@module”携带的所有“病毒@provides”放入“寄生包daggerxxxComponent”内;二、内部的唯一一个方法指明谁是寄“主”,也就是说明确了和谁的生命周期是等同的。
@Component(modules={BehaviourModule.class, ArgModule.class}) //添加组件,使用Module内各@provides
public interface BehaviourComponent {
void inject(Behaviour1Activity activity);//伴随的生命周期
}
@Inject 英文本意就是“注入”,他是从“寄生包”注入到“寄主”。理解反之后是如何都想不通的。它就是寄主的叛徒,它会把“寄生包”里相同的病毒直接映射过来(是不是映射我不知道,就是那么个意思,理解就行,别较真),从而不需要再去new,当有变化时也不需要考虑“寄主端”。
@Named("A")// 使用同样标记“A”的对象
@Inject //可以理解为该标记从DaggerBehaviourComponent中拿数据
Animal animal;
@Inject //因为只有一个,不需要@Named标记
Food food;
综合起来说,Module定义对象提供集,提供由@Provides标注的对象;这几个集将会被xxxComponent接口收录,在自动生成的DaggerXXXComponent类中继承,为@Provides并@inject的对象提供一个Provide<实际对象>的句柄(参照任意一个DaggerxxxComponent的源码都可以发现这一点,同样的“寄主”也会提供一个句柄);在使用@Inject的时候,通过某些原理将Provide<实际对象>赋了过来。
还有一点必须要说的是:在寄主中,实现DaggerxxxComponent的时候,凡是其包含的没有无参构造器(或者说只有有参构造器)的module必须显式的传入该Module对象的实例,否则空指针,参考如下系统生成的build()方法代码:
public BehaviourComponent build() {
if (behaviourModule == null) { //系统会自动新建
this.behaviourModule = new BehaviourModule();
}
if (argModule == null) {//ArgModule没有无参构造器,系统不会自动添加
throw new IllegalStateException("argModule must be set");
}
return new DaggerBehaviourComponent(this);
}
这次是第一版,今天就写到这里,本应该有插图、有源码的,那样才更有助于理解。可是因为是周五晚上了,不想搞那么多,就写到这好了。回头会把插图和源码补上。
觉得有用,请点个赞,评个论,谢谢啦!