Dagger2的基礎使用與原理

Dagger2的基礎使用與原理

前言

Dagger 2 是基於 Java Specification Request(JSR) 330標準。利用 JSR 註解在編譯時生成代碼,來注入實例完成依賴注入

什麼是依賴注入?
是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。

基礎使用

1. Gradle配置

implementation 'com.google.dagger:dagger:2.27'
annotationProcessor 'com.google.dagger:dagger-compiler:2.27'

2.創建依賴對象(在這裏也稱爲成員對象)與調用者

依賴對象

public class Chair {

    private String color;

    private String height;

    public Chair(String color, String height) {
        this.color = color;
        this.height = height;
    }

    public String getColor() {
        return color;
    }

    public String getHeight() {
        return height;
    }
}

調用者

/**
 * 1,創建Module(依賴對象庫)  提供依賴的對象實例
 * 2,創建Component(連接依賴對象庫與調用者的橋樑)
 * 3,使用@Inject在調用者中注入對象並綁定調用者
 */

public class HouseActivity extends Activity {
    @Inject
    Chair chair;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_house);
        //綁定component
        DaggerChairHouseComponent.create().injectHouse(this);

      
    }
}

3. 創建Module依賴對象庫,作用:提供依賴對象的實例

/**
 * 提供屬性注入對象的實例
 */
@Module
public class ChairCreatModule {

    /**
     * 提供屬性(桌子)的生成
     * @return
     */
    @Provides
    public  Chair providesChair(){
        return new Chair("紅色","1m");
    }

}

@Provides
  意思就是提供,顯然在 Dagger2 中它的作用就是提供依賴。被標註函數的返回值既是依賴對象實例。
@Module
  模塊,用 @Provides 註解的依賴必須存在一個用 @Module 註解的類中。@Module還可以包括其他module,如@Module(includes =xxx )
  
4. 創建Component橋樑,作用:連接調用者與Module依賴對象庫的橋樑

/**
 * 連接器需要綁定Module,也可以綁定多個Module,同時也可以dependencies其他Component連接器
 */
@Component(modules = ChairCreatModule.class)
public interface ChairHouseComponent {

    /**
     * 連接器作爲一箇中間件,已經綁定依賴對象庫了,那如何與調用者綁定呢?
     *
     * 通過提供一個方法
     * 1,返回值爲void
     * 2,方法的參數爲調用者對象(HouseActivity),不能是 HouseActivity 的父類或子類
     * 3,接口名任意
     * @param activity
     */

    void injectHouse(HouseActivity activity);

}

@Component
1,橋樑連接器, 連接調用者(HouseActivity)和依賴對象庫(ChairCreateModule)的橋樑。
2,注意使用@Component標註,必要綁定module關聯,同時也可以關聯多個module.

連接器作爲一箇中間件,已經綁定依賴對象庫了,那如何與調用者綁定呢?
是的,通過定義接口函數來綁定調用者

接口函數定義有哪些要求?
1,返回值爲void
2,方法的參數爲調用者對象(HouseActivity),不能是HouseActivity 的父類或子類
3,接口名任意

5. 調用接口函數綁定

 //綁定component
 DaggerChairHouseComponent.create().injectHouse(this);

以上就是dagger簡單的一個使用

實現原理

dagger在build時會在build/generated/source/apt產生3個文件,我們看下這3個文件。

ChairCreatModule_ProvidesChairFactory.java

// Generated by Dagger (https://dagger.dev).
package com.jet.daggertest.basic_use;

import dagger.internal.Factory;
import dagger.internal.Preconditions;

@SuppressWarnings({
    "unchecked",
    "rawtypes"
})
/**
 * 成員屬性的工廠類
 * 主要是創建成員屬性類對象
 */
public final class ChairCreatModule_ProvidesChairFactory implements Factory<Chair> {
  private final ChairCreatModule module;

  public ChairCreatModule_ProvidesChairFactory(ChairCreatModule module) {
    this.module = module;
  }

  @Override
  public Chair get() {
    return providesChair(module);
  }

  public static ChairCreatModule_ProvidesChairFactory create(ChairCreatModule module) {
    return new ChairCreatModule_ProvidesChairFactory(module);
  }

  public static Chair providesChair(ChairCreatModule instance) {
    return Preconditions.checkNotNull(instance.providesChair(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

可以看出,這是一個工廠類,通過提供get()方法向外提供依賴對象實例。結論是該工廠類主要是創建成員屬性類對象。

HouseActivity_MembersInjector.java

// Generated by Dagger (https://dagger.dev).
package com.jet.daggertest.basic_use;

import dagger.MembersInjector;
import dagger.internal.InjectedFieldSignature;
import javax.inject.Provider;

@SuppressWarnings({
    "unchecked",
    "rawtypes"
})
/**
 * 成員屬性注入類
 * 主要工作是獲得調用者並初始化被@Inject標註的成員
 */
public final class HouseActivity_MembersInjector implements MembersInjector<HouseActivity> {
  //
  private final Provider<Chair> chairProvider;

  public HouseActivity_MembersInjector(Provider<Chair> chairProvider) {
    this.chairProvider = chairProvider;
  }

  public static MembersInjector<HouseActivity> create(Provider<Chair> chairProvider) {
    return new HouseActivity_MembersInjector(chairProvider);}

  @Override
  public void injectMembers(HouseActivity instance) {
    //獲得調用者,並設置賦予調用者中被@Inject標註的成員屬性對象
    injectChair(instance, chairProvider.get());
  }

  @InjectedFieldSignature("com.jet.daggertest.basic_use.HouseActivity.chair")
  public static void injectChair(HouseActivity instance, Chair chair) {
    //賦予調用者中被@Inject標註的成員屬性對象
    instance.chair = chair;
  }
}

可以看出injectChair(HouseActivity instance, Chair chair)是一個注入依賴對象的方法,賦予調用者中被@Inject標註的成員屬性對象實例。結果:這是一個成員屬性注入類。

對象注入類與依賴對象都有了,接下來就是如何把他們關聯起來,這就是component的操作了。

DaggerChairHouseComponent.java

// Generated by Dagger (https://dagger.dev).
package com.jet.daggertest.basic_use;

import dagger.internal.Preconditions;

@SuppressWarnings({
    "unchecked",
    "rawtypes"
})
public final class DaggerChairHouseComponent implements ChairHouseComponent {
  private final ChairCreatModule chairCreatModule;

  private DaggerChairHouseComponent(ChairCreatModule chairCreatModuleParam) {
    this.chairCreatModule = chairCreatModuleParam;
  }

  public static Builder builder() {
    return new Builder();
  }

  public static ChairHouseComponent create() {
    return new Builder().build();
  }

  @Override
  public void injectHouse(HouseActivity activity) {
    injectHouseActivity(activity);}

  /**
   * 作爲橋接成員屬性注入類(HouseActivity_MembersInjector)與成員屬性工廠類(ChairCreatModule_ProvidesChairFactory)
   * @param instance
   * @return
   */
  private HouseActivity injectHouseActivity(HouseActivity instance) {
    //獲取調用者
    //並通過成員屬性的工廠類獲得成員對象
    //最後調用成員屬性注入類完成注入
    HouseActivity_MembersInjector.injectChair(instance, ChairCreatModule_ProvidesChairFactory.providesChair(chairCreatModule));
    return instance;
  }

  public static final class Builder {
    private ChairCreatModule chairCreatModule;

    private Builder() {
    }

    public Builder chairCreatModule(ChairCreatModule chairCreatModule) {
      this.chairCreatModule = Preconditions.checkNotNull(chairCreatModule);
      return this;
    }

    public ChairHouseComponent build() {
      if (chairCreatModule == null) {
        this.chairCreatModule = new ChairCreatModule();
      }
      return new DaggerChairHouseComponent(chairCreatModule);
    }
  }
}

我們看下HouseActivity_MembersInjector.injectChair(instance, ChairCreatModule_ProvidesChairFactory.providesChair(chairCreatModule)); 這個方法,獲取調用者,並通過成員屬性的工廠類獲得成員對象,最後調用成員屬性注入類完成注入。

粗糙的描繪了一下圖片:
在這裏插入圖片描述

結論:
1,成員屬性注入類(HouseActivity_MembersInjector):負責將成員屬性chair對象賦予調用者中以@Inject標註的對象給予初始化。
2,成員屬性工廠類(ChairCreatModule_ProvidesChairFactory):負責生產成員屬性chair對象。
3,橋樑(DaggerChairHouseComponent):通過成員屬性工廠類(ChairCreatModule_ProvidesChairFactory)獲得成員對象,並調用成員屬性注入類(HouseActivity_MembersInjector)
的方法HouseActivity_MembersInjector.injectChair(HouseActivity instance, Chair chair)給調用者注入成員對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章