前言
之前記錄了最簡單的Dagger 2 使用,現(xiàn)在記錄一下面對多層依賴時的問題,同時配合 @Module 進行注入的情況。
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<ClassRoom> classRoomProvider;// 多出一個 clssRoomProvider
...
private void initialize(final Builder builder) {
// 初始化方法變化,需要先初始化 classRoomProvider,然后再創(chuàng)建 mainActivityMembersInjector
this.classRoomProvider = ClassRoom_Factory.create(User_Factory.create());
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(classRoomProvider);
}
...
注意: 此處對
classRoomProvider初始化 需要調(diào)用到他所依賴的User所生成的User_Factory這里也是處理依賴的地方,當
ClassRoom生成需要User時,需要先提供User的生成者,也就是User_Factory
(2) MainActivity_MemberInjector.java,變化也不大
因為去掉了 @Inject User mUser; 這行,因此 Provider<User> mUserProvider 也就消失了。
其余部分,主要是從 User 轉換到 ClassRoom 。具體可以參考下面代碼
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<ClassRoom> mClassRoomProvider;
public MainActivity_MembersInjector(Provider<ClassRoom> mClassRoomProvider) {
assert mClassRoomProvider != null;
this.mClassRoomProvider = mClassRoomProvider;
}
public static MembersInjector<MainActivity> create(Provider<ClassRoom> 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<ClassRoom> mClassRoomProvider) {
instance.mClassRoom = mClassRoomProvider.get();
}
}
(3) 總結
所以綜上,當需要注入的對象,依賴另一個對象時,Dagger 2 編譯 生成的代碼,和原本的方法區(qū)別不是很大
最大變化主要是初始化 DaggerUserComponent 時候,多了對 classRoomProvider 的初始化賦值。
即 A 依賴 B 時,Dagger 在生成 Component 實例的時候,會調(diào)用 B 的B_Factory來生成 mAProvider
然后才能對 mainActiivtyMembersInjector 進行初始化
B 配合@Module 解決多層依賴
1. 總述
@Module 作用,某個模塊依賴的提供者,@Provides 配合使用,其主要是下面兩種情況:
- 需要的依賴并沒有存在實例,需要
new出來 - 需要的依賴來自已經(jīng)創(chuàng)建的或者已存在的對象
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();
// 注意此處調(diào)用方式已經(jīng)變了,需要外部自己傳入標記的 xxModule 類
DaggerUserComponent.builder()
.subjectModule(mSubjectModule)
.build().injectTo(this);
mUserAgeTv.setText("" + mSubject.mClassRoom.getUser().getAge());
3. 查看該部分內(nèi)容對應生成的代碼
加入的修改的類有些多,所以再看一次其生成代碼的對應關系
(1) SubjectModule.java => SubjectModule_ProvideSubjectFactory.java
@Provides Subject provideSubject(ClassRoom classRoom) 該注解,確定了 生成的 xxx_ProvidexxxFactory 需要用到的依賴,此處是ClassRoom 類,對應的是 ClassRoom_Factory ,下面具體的代碼中也可看出
public final class SubjectModule_ProvideSubjectFactory implements Factory<Subject> {
private final SubjectModule module;
private final Provider<ClassRoom> classRoomProvider;// @provides 標記的函數(shù)所需要的依賴
public SubjectModule_ProvideSubjectFactory(
SubjectModule module, Provider<ClassRoom> classRoomProvider) {
assert module != null;
this.module = module;
assert classRoomProvider != null;
this.classRoomProvider = classRoomProvider;
}
@Override
public Subject get() {
// get方法不一樣,不是直接 new ,而是調(diào)用 SubjectModule.provideSubject() 方法
// 而該方法依賴 ClassRoom 對象,因此需要調(diào)用到 classRoomProvider.get 來獲取 ClassRoom 的實例
return Preconditions.checkNotNull(
module.provideSubject(classRoomProvider.get()),
"Cannot return null from a non-@Nullable @Provides method");
}
// 該部分生成方法和以前的 ClassRoom_Factory 一樣,有外層依賴,需要傳入
public static Factory<Subject> create(
SubjectModule module, Provider<ClassRoom> classRoomProvider) {
return new SubjectModule_ProvideSubjectFactory(module, classRoomProvider);
}
}
(2) UserComponent.java => DaggerUserComponent.java
主要關注點三個
a.該部分添加了@Component(modules = SubjectModule.class) ,整體調(diào)用上有變化,需要外部傳入 SubjectModule的實例
b.同時多了一個 Provider<Subject> provideSubjectProvider
c. 因為Dagger2 通過上述 (1) 中 @Provides 所標記的函數(shù),所需要的依賴判斷出需要ClassRoom的實例提供者 ,因此有classRoomProvider
....
private Provider<Subject> 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 會自己創(chuàng)建一個
this.subjectModule = new SubjectModule();
}
return new DaggerUserComponent(this);
}
// 1 構造的時候可以傳入 subjectModule
public Builder subjectModule(SubjectModule subjectModule) {
this.subjectModule = Preconditions.checkNotNull(subjectModule);
return this;
}
}
...
...
故而,配合調(diào)用鏈來看,上述代碼注釋中的 1,2需要注意
因為外部傳入的 subjectModule 是由自己創(chuàng)建,控制的
而如果沒有傳入,
dagger會自動創(chuàng)建一個如果當前
DaggerUserComponent被重復使用,其subjectModule也會一直重復使用同一個該部分具體看需求,不同情況不同使用
(3)MainActivity.java => MainActivity_MembersInjector.java
其中 MainActivity_MembersInjecto.java 修改很小,和上面A部分情況類似
因為去掉了 @Inject ClassRoom mClassRoom; 故而就是把A部分的中mClassRoomProvider => mSubjectModule
3. 第二種情況處理
我們需要從外面?zhèn)魅胱约?code>new 的實例,再調(diào)用 Dagger 來生成對應的實例。
可以借助 SubjectModule 構造函數(shù),或者方法進行放入,如下:
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,一個標注的函數(shù)會生成xxxModule_providexxxFactory 從而為 Component 注入提供實例。
然后附上Component Module 和被注入類的整體關系圖,因為上面寫的比較詳細,此處就只給一個整體圖了

一家之言,如有錯誤,輕噴。