前言
之前记录了最简单的Dagger 2
使用,现在记录一下面对多层依赖时的问题,同时配合 @Module
进行注入的情况。
A 多层依赖情况
该部分代码A
1. 多层依赖情况模拟
添加 ClassRoom
类
public class ClassRoom {
User mUser;
@Inject
public ClassRoom(User user){
this.mUser = user;
}
public User getUser() {
return mUser;
}
public void setUser(User user) {
mUser = user;
}
}
修改 MainActivity.java
...
//@Inject User mUser;// 注释掉这行
@Inject ClassRoom mClassRoom;// 添加这行注入
...
mUserAgeTv.setText("" + mClassRoom.getUser().getAge());
// 修改获取方式,测试注入是否成功
...
2. 生成代码对比
ClassRoom.java
=> ClassRoom_Factory.java
编译,查看生成代码,多出一个 ClassRoom_Factory
,效果和对 User
构造方法的注入是一样的。
重点关注 DaggerUserComponent
和 MainActivity_MemberInjector
的变化
(1) DaggerUserComponent.java
变化不大,主要是多了一个 Provider以及对应的初始化
private Provider classRoomProvider;// 多出一个 clssRoomProvider
...
private void initialize(final Builder builder) {
// 初始化方法变化,需要先初始化 classRoomProvider,然后再创建 mainActivityMembersInjector
this.classRoomProvider = ClassRoom_Factory.create(User_Factory.create());
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(classRoomProvider);
}
...
注意: 此处对
classRoomProvider
初始化 需要调用到他所依赖的User
所生成的User_Factory
这里也是处理依赖的地方,当
ClassRoom
生成需要User
时,需要先提供User
的生成者,也就是User_Factory
(2) MainActivity_MemberInjector.java
,变化也不大
因为去掉了 @Inject User mUser;
这行,因此 Provider
也就消失了。
其余部分,主要是从 User
转换到 ClassRoom
。具体可以参考下面代码
public final class MainActivity_MembersInjector implements MembersInjector {
private final Provider mClassRoomProvider;
public MainActivity_MembersInjector(Provider mClassRoomProvider) {
assert mClassRoomProvider != null;
this.mClassRoomProvider = mClassRoomProvider;
}
public static MembersInjector create(Provider mClassRoomProvider) {
return new MainActivity_MembersInjector(mClassRoomProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mClassRoom = mClassRoomProvider.get();
}
public static void injectMClassRoom(
MainActivity instance, Provider mClassRoomProvider) {
instance.mClassRoom = mClassRoomProvider.get();
}
}
(3) 总结
所以综上,当需要注入的对象,依赖另一个对象时,Dagger 2
编译 生成的代码,和原本的方法区别不是很大
最大变化主要是初始化 DaggerUserComponent
时候,多了对 classRoomProvider
的初始化赋值。
即 A
依赖 B
时,Dagger
在生成 Component
实例的时候,会调用 B
的B_Factory
来生成 mAProvider
然后才能对 mainActiivtyMembersInjector
进行初始化
B 配合@Module
解决多层依赖
该部分代码B
1. 总述
@Module
作用,某个模块依赖的提供者,@Provides
配合使用,其主要是下面两种情况:
- 需要的依赖并没有存在实例,需要
new
出来 - 需要的依赖来自已经创建的或者已存在的对象
2.具体使用模拟
此处先考虑实例 需要 new
出来这种情况。
添加 Subject.java
public class Subject {
String mName;
String mId;
ClassRoom mClassRoom;
User mUser;
public Subject(ClassRoom classRoom){
this.mName = "";
this.mId = "";
this.mClassRoom = classRoom;
this.mUser = classRoom.getUser();
}
...
...
}
添加SubjectModule.java
@Module
public class SubjectModule {
public SubjectModule(){
}
@Provides Subject provideSubject(ClassRoom classRoom){
return new Subject(classRoom);
}
}
修改UserComponent.java
@Component(modules = SubjectModule.class)// 修改加入 modules 依赖
...
修改 MainActivity.java
// @Inject User mUser;
// @Inject ClassRoom mClassRoom;
// 注释掉上面两行,添加 mSubject 的注入
@Inject Subject mSubject;
SubjectModule mSubjectModule;
...
...
mSubjectModule = new SubjectModule();
// 注意此处调用方式已经变了,需要外部自己传入标记的 xxModule 类
DaggerUserComponent.builder()
.subjectModule(mSubjectModule)
.build().injectTo(this);
mUserAgeTv.setText("" + mSubject.mClassRoom.getUser().getAge());
3. 查看该部分内容对应生成的代码
加入的修改的类有些多,所以再看一次其生成代码的对应关系
(1) SubjectModule.java
=> SubjectModule_ProvideSubjectFactory.java
@Provides Subject provideSubject(ClassRoom classRoom)
该注解,确定了 生成的 xxx_ProvidexxxFactory
需要用到的依赖,此处是ClassRoom
类,对应的是 ClassRoom_Factory
,下面具体的代码中也可看出
public final class SubjectModule_ProvideSubjectFactory implements Factory {
private final SubjectModule module;
private final Provider classRoomProvider;// @provides 标记的函数所需要的依赖
public SubjectModule_ProvideSubjectFactory(
SubjectModule module, Provider classRoomProvider) {
assert module != null;
this.module = module;
assert classRoomProvider != null;
this.classRoomProvider = classRoomProvider;
}
@Override
public Subject get() {
// get方法不一样,不是直接 new ,而是调用 SubjectModule.provideSubject() 方法
// 而该方法依赖 ClassRoom 对象,因此需要调用到 classRoomProvider.get 来获取 ClassRoom 的实例
return Preconditions.checkNotNull(
module.provideSubject(classRoomProvider.get()),
"Cannot return null from a non-@Nullable @Provides method");
}
// 该部分生成方法和以前的 ClassRoom_Factory 一样,有外层依赖,需要传入
public static Factory create(
SubjectModule module, Provider classRoomProvider) {
return new SubjectModule_ProvideSubjectFactory(module, classRoomProvider);
}
}
(2) UserComponent.java
=> DaggerUserComponent.java
主要关注点三个
a.该部分添加了@Component(modules = SubjectModule.class)
,整体调用上有变化,需要外部传入 SubjectModule
的实例
b.同时多了一个 Provider
c. 因为Dagger2
通过上述 (1) 中 @Provides
所标记的函数,所需要的依赖判断出需要ClassRoom
的实例提供者 ,因此有classRoomProvider
....
private Provider provideSubjectProvider;
...
...
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.classRoomProvider = ClassRoom_Factory.create(User_Factory.create());
this.provideSubjectProvider =
SubjectModule_ProvideSubjectFactory.create(builder.subjectModule, classRoomProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(provideSubjectProvider);
}
@Override
public void injectTo(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private SubjectModule subjectModule;
...
public UserComponent build() {
if (subjectModule == null) {// 2 如果为空,dagger 会自己创建一个
this.subjectModule = new SubjectModule();
}
return new DaggerUserComponent(this);
}
// 1 构造的时候可以传入 subjectModule
public Builder subjectModule(SubjectModule subjectModule) {
this.subjectModule = Preconditions.checkNotNull(subjectModule);
return this;
}
}
...
...
故而,配合调用链来看,上述代码注释中的 1,2需要注意
因为外部传入的 subjectModule 是由自己创建,控制的
而如果没有传入,
dagger
会自动创建一个如果当前
DaggerUserComponent
被重复使用,其subjectModule
也会一直重复使用同一个该部分具体看需求,不同情况不同使用
(3)MainActivity.java
=> MainActivity_MembersInjector.java
其中 MainActivity_MembersInjecto.java
修改很小,和上面A部分情况类似
因为去掉了 @Inject ClassRoom mClassRoom;
故而就是把A部分的中mClassRoomProvider
=> mSubjectModule
3. 第二种情况处理
我们需要从外面传入自己new
的实例,再调用 Dagger
来生成对应的实例。
可以借助 SubjectModule
构造函数,或者方法进行放入,如下:
SubjectModule mSubjectModule = new SubjectModule(new ClassRoom());
DaggerUserComponent.builder()
.subjectModule(mSubjectModule)
.build().injectTo(this);
...
ClassRoom mClassRoom;
public SubjectModule(ClassRoom classRoom){
mClassRoom = classRoom;
}
...
@Provides Subject provideSubject(){
return new Subject(mClassRoom);
}
//也可以给出对外接口
//public void setClassRoom(ClassRoom classRoom){
// this.mClassRoom = classRoom;
//}
...
以上就是关于 Dagger
在面对多层依赖的简单情况下,生成代码的分析
其中关于 @Module
@Provides
两个注解是关键部分,一个标注当前类是Module
,一个标注的函数会生成xxxModule_providexxxFactory
从而为 Component
注入提供实例。
然后附上Component
Module
和被注入类的整体关系图,因为上面写的比较详细,此处就只给一个整体图了
一家之言,如有错误,轻喷。
该部分代码A
该部分代码B