dagger2 學習(二)

前言

之前記錄了最簡單的Dagger 2 使用,現(xiàn)在記錄一下面對多層依賴時的問題,同時配合 @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 構造方法的注入是一樣的。

重點關注 DaggerUserComponentMainActivity_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)用 BB_Factory來生成 mAProvider

然后才能對 mainActiivtyMembersInjector 進行初始化

B 配合@Module 解決多層依賴

該部分代碼B

1. 總述

@Module 作用,某個模塊依賴的提供者,@Provides 配合使用,其主要是下面兩種情況:

  1. 需要的依賴并沒有存在實例,需要 new 出來
  2. 需要的依賴來自已經(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 和被注入類的整體關系圖,因為上面寫的比較詳細,此處就只給一個整體圖了

dagger2 學習(二)

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

該部分代碼A

該部分代碼B

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Dagger2 轉載請注明原作者,如果你覺得這篇文章對你有幫助或啟發(fā),可以關注打賞。 前言本文翻譯自Google ...
    輕云時解被占用了閱讀 6,931評論 4 31
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,094評論 25 709
  • 前言 該部分代碼 記錄一下自己的基本的認識,Dagger 2 的目的是為了解決依賴問題 當我們申明一個 User ...
    搬代碼白言午閱讀 483評論 0 0
  • 這幾天心里很煩,人生的諸多不順總是在不經(jīng)意的襲來,社會繁忙凝成了心中沉重的困惑,我自己仿佛成了一只孤獨而又疲...
    玫瑰心閱讀 224評論 0 1

友情鏈接更多精彩內(nèi)容