前言
Dagger2进阶-范围的控制(Scope和Singleton)
项目源码传送门
根据前面两篇文章的解读,大家一定对Dagger2的用法有自己的理解和应用,但是日常开发过程中会根据业务的复杂度,我们会出现各种各样的问题,这就要求大家对Dagger2的原理和编译生成的源码进行解读找出问题的答案。下面我们会分几个阶段进行源码解读,从简单到困难。
@Inject作用在构造方法上
当项目中只有一个@Inject的时候,我们会看到什么呢,以Goods为列子:
根据上图,我们很清晰的知道,如果只用@Inject会生成一个工厂类,这个工厂类也非常简单就是通过get()方法生成一个对象。
@Inject作用字段属性上
当我们使用@Inject获取一个对象的时候,我们看看发生了什么,编译:
我们可以看到,生成了一个XXX_MembersInjector:
其中,我们看构造方法就是传入工厂类赋值,create就是创建一个MemberInjector对象,其实最核心的是以下代码:
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mGoods = mGoodsProvider.get();
}
我们可以看到instance其实就是我们需要Goods对象的Activity,instance.mGoods = mGoodsProvider.get();语句就是为activity对象中的mGoods创建一个新的Goods对象,而对象Goods通过工厂类提供,So,XXX_MembersInjector就是赋值的作用,这里就说明为什么我们@Inject修饰的字段为什么不能使用private的权限了。
我们做一个尝试,我们在同一个Activity注入三个Goods对象会怎样变化呢?
如果自己尝试可以看出来,其他逻辑什么都没变化,变化的是他也是赋值了三次,生成了三次新的对象。
看完以上源码我们解决如下疑问:
1.为什么默认是多例的?
因为工厂类get(),返回是new XX(),直接赋值肯定是不是单例;
2.为什么需要@Component才能获取对象的引用?
因为我们不知道MainActivity 这个对象是什么 得有人告诉我,@Component就提供了这个职能。
使用了@Component
当我们第一次使用@Component什么都不添加会产生什么代码呢?
看上面可以比较出,生成了一个以Dagger+XXX的类,这个类就是对外的注入类。
看代码也是很好解读的:
首先代码模板有一个建造类,使用建造类生成一个Dagger+XXX对象
然后调用构造方法里面的initialize(final Builder builder)初始化mainActivityMembersInjector对象,mainActivityMembersInjector对象就是之前的XXX_MembersInjector
最后我们看看,我们Activity最不可少的inject(object)方法,这个方法就是调用XXX_MembersInjector里面的injectMembers这里就把我们的activity和Goods对象赋值上了,所以@Component的职责,就是一个中介,我更倾向于把他当成一个管理类。
使用了@Module和@Provides
我们看到,类没有增加,还是三个,只是工厂类的命名修改了,我们来查看一下里面的代码,先看工厂类。。
跟用@Inject的区别在于,这里多了个Module对象,跟@Injetc一样 也是通过get()获取到一个对象,只是这里再用一个Module做了衔接。
XX_MembersInjector对象没有改变任何代码也是用来赋值引用。
Dagger+XX这个类主要改变在创建类中,多了一个ObjectModule对象,这个对象,就是我们的模块对象,是提供新建对象,根据传入的Module对象传入工厂类中,生成相应的对象。