项目中有使用dagger2,自己一直处于一个只会套模板使用的状态,项目做完研究了下dagger2注入流程的原理,写一下自己的心得。不熟悉dagger2使用流程的同学可以先去熟悉下使用流程,这里不做具体探讨。
dagger2版本使用的是2.14.1,旧版本生成的代码可能会有所不同,但逻辑基本相同
一、注入流程
1.创建module,这里简单地创建了一个string对象,编译过后就会生成CommonModule_ProvideContentFactory类
CommonModule_ProvideContentFactory类 实现了Factory, 泛型是provider返回的对象,构造方法中传入了module对象。其中get()方法调用了module中的provideContent,返回了这个方法的结果
2.创建CommonComponent,构建后生成DaggerCommonComponent 以及Dagger2Activity_MembersInjector
先看下Dagger2Activity_MembersInjector ,构造方法中传入了利用第一步生成的CommonModule_ProvideContentFactory封装的Provider对象contentProvider,在MembersInjector方法中调用了contentProvider.get(),最终就调用到了module中的方法,并把这个值赋值给需要注入的实例,实例就是Dagger2Activity
public final class Dagger2Activity_MembersInjector implements MembersInjector<Dagger2Activity> {
private final Provider<String> contentProvider;
//构造方法中传入contentProvider
public Dagger2Activity_MembersInjector(Provider<String> contentProvider) {
this.contentProvider = contentProvider;
}
public static MembersInjector<Dagger2Activity> create(Provider<String> contentProvider) {
return new Dagger2Activity_MembersInjector(contentProvider);
}
@Override
public void injectMembers(Dagger2Activity instance) {
injectContent(instance, contentProvider.get());//contentProvider.get()获取到module实例对象中提供的具体值
}
//赋值给注入对象的成员变量
public static void injectContent(Dagger2Activity instance, String content) {
instance.content = content;
}
}
接下来看DaggerCommonComponent和Dagger2Activity
Dagger2Activity ,这里箭头注入了一个string对象,初始化时调用了DaggerCommonComponent的inject方法,调用这个方法后就完成了注入
DaggerCommonComponent ,这是注入过程中的一个桥梁。内部定义了一个Builder对象,Builder对象里有我们在CommonComponent里定义的module成员变量,activity调用commonModule对module赋值。
赋值完就调用build返回DaggerCommonComponent实例化对象。DaggerCommonComponent的构造方法里,利用Builder里的module对象 创建第一步里的provider对象 。
再调用DaggerCommonComponent的inject方法,inject方法里调用了Dagger2Activity_MembersInjector 里的静态方法injectContent,对Dagger2Activity里的content赋值,content的值来自provideContentProvider.get(),到这里赋值就完成了
public final class DaggerCommonComponent implements CommonComponent {
private Provider<String> provideContentProvider;
private DaggerCommonComponent(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private Dagger2Presenter getDagger2Presenter() {
return new Dagger2Presenter(provideViewProvider.get());
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideContentProvider =
DoubleCheck.provider(CommonModule_ProvideContentFactory.create(builder.commonModule));
}
@Override
public void inject(Dagger2Activity activity) {
injectDagger2Activity(activity);
}
private Dagger2Activity injectDagger2Activity(Dagger2Activity instance) {
Dagger2Activity_MembersInjector.injectContent(instance, provideContentProvider.get());
return instance;
}
public static final class Builder {
private CommonModule commonModule;//在CommonComponent里定义的module
private Builder() {}
//返回DaggerCommonComponent实例化对象
public CommonComponent build() {
if (commonModule == null) {
throw new IllegalStateException(CommonModule.class.getCanonicalName() + " must be set");
}
return new DaggerCommonComponent(this);
}
//activity里调用这个方法对module进行赋值
public Builder commonModule(CommonModule commonModule) {
this.commonModule = Preconditions.checkNotNull(commonModule);
return this;
}
}
}
关于DoubleCheck
provider(Provider<T> delegate)调用了构造器方法,构造器中将传入的Provider对象保存起来了,调用get()时会调用保存的provider对象的get(),实际上就是调用工厂方法的get()拿到对象,这样就实现了懒加载,在需要的时候调用get(),这时才会调用工厂方法的get(),因为真正创建对象的细节是封装在工厂类的get()中的,同时,它会将得到的对象缓存起来,这样下次调用就不需要再调用工厂类创建对象了。
public static <T> Provider<T> provider(Provider<T> delegate) {
...
return new DoubleCheck<T>(delegate);
}
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the provider
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
/* Get the current instance and test to see if the call to provider.get() has resulted
* in a recursive call. If it returns the same instance, we'll allow it, but if the
* instances differ, throw. */
Object currentInstance = instance;
if (currentInstance != UNINITIALIZED && currentInstance != result) {
throw new IllegalStateException("Scoped provider was invoked recursively returning "
+ "different results: " + currentInstance + " & " + result + ". This is likely "
+ "due to a circular dependency.");
}
instance = result;
/* Null out the reference to the provider. We are never going to need it again, so we
* can make it eligible for GC. */
provider = null;
}
}
}
return (T) result;
}
流程总结
首先创建好module 和Component 类,以及需要注入的activity,编译后生成相关的类
在activity初始化中调用注入方法,从这行代码开始分析流程
DaggerCommonComponent.builder().commonModule(new CommonModule(this)).build().inject(this);
1.DaggerCommonComponent.builder()获取到Builder对象
2.commonModule(new CommonModule(this)),给Builder力的module成员变量赋值
3.build(),创建了DaggerCommonComponent对象,DaggerCommonComponent的构造方法中利用Builder
里的module对象 创建里的provider对象,provider构造参数是实例化的module,其中get()方法返回module里@provider标记的方法返回值
4.inject(this),调用Dagger2Activity_MembersInjector里的inject方法,inject方法参数一是activity,
参数二是provider.get()获取到的具体值,然后赋值给activity里@inject标记的成员变量
二、关于注入有三种方式
构造方法注入:在类的构造方法前面注释@Inject
成员变量注入:在类的成员变量(非私有)前面注释@Inject
函数方法注入:在函数前面注释@Inject
上面例子说明的是,在类的成员变量(非私有)前面注释@Inject
1.接下去看下在类的构造方法前面注释@Inject
创建present类,需要传入一个view对象,在构造方法注释@Inject
dagger2activity中多了一行注入代码
module第一步上面已经写好了,编译后生成CommonModule_ProvideViewFactory
Dagger2Activity_MembersInjector中增加了present相关的注入方法,与string 的注入方法一样
DaggerCommonComponent中多了present的注入方法,注意在injectDagger2Activity里注入present时调用了getDagger2Presenter,而这个方法里new了一个Dagger2Presenter,参数传的是从provider中获得的view,其他步骤和成员变量注入一样
2.在函数前面注释@Inject
dagger2activity中修改,在一个方法中注释@Inject,并把注入的值赋值给content
Dagger2Activity_MembersInjector 中箭头处的赋值方法由变量赋值变成了方法调用,其他逻辑不变
DaggerCommonComponent里的逻辑没有变化
总结
在类的成员变量(非私有)前面注释@Inject 和在函数前面注释@Inject ,注入的逻辑流程一样,只是赋值时一个是成员变量赋值,一个是调用方法
在类的构造方法前面注释@Inject,Component会增加一个方法new 出这个对象
这里说明一下,我dagger2版本使用的是2.14.1。而在2.11版本里,new出present对象的方法是在provider里,Component里使用的是Dagger2Activity_MembersInjector.injectMembers方法,而不是具体的静态方法,其他逻辑一样