Dagger2 知識梳理(3) 使用 dependencies 和 @SubComponent 完成依賴注入

澤毛發表於2017-12-21

一、前言

Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中,我們介紹了兩種依賴注入的方式,其中第二種是通過給注入器Component指定Module,再由Module提供建立例項的方法,來實現依賴注入,這是一種“自給自足”的方式,在這種情況下,我們的Component是這麼宣告的:

指定 Module
除此之外,還有另外兩種方式,讓Component可以通過其他的Component完成依賴注入,可以劃分為:依賴方式繼承方式

  • 通過依賴方式實現時,需要在Component中指定它所依賴的Component名字:
    依賴方式下的 Component
    而被依賴的Component需要宣告它可以提供哪些類的例項化,因此它需要在Component中宣告一些返回值為這些類的方法:
    依賴方式下的被依賴 Component
  • 通過繼承方式時實現時,子Component類需要用@SubComponent宣告,這種情況下,它一般類似於下面這樣:
    繼承方式下的子 SubComponent
    並且我們不能直接建立該Component的例項來完成依賴注入,而是需要由父Component例項提供一個getXXX來將這個SubComponent返回給使用者,SubComponent自動擁有了父Component注入物件的能力。
    繼承方式下的父 Component

依賴方式和繼承方式的共同點就是,它們都是通過別的Component來完成依賴注入的。下面,我們先通過兩個簡單的例子,來演示如何使用這兩種方式完成注入,這篇文章的完整程式碼可以從 Dagger2Sample 的第三章獲取。

二、使用依賴方式完成注入

2.1 定義被依賴的 DependencyComponent

當採用“依賴方式”來實現時,首先需要定義一個被依賴的Component,我們用DependencyComponent來實現,它可以提供一個資料來源,即DependencySource

public class DependencySource {
    public String getData() {
        return "獲取到來自依賴 Component 的資料";
    }
}
複製程式碼

和前面介紹的一樣,該資料來源通過一個Component和一個Module來提供:

@Component(modules = DependencyModule.class)
public interface DependencyComponent {
    DependencySource getDependencySource();
}
複製程式碼
@Module
public class DependencyModule {
    @Provides
    DependencySource provideDependencySource() {
        return new DependencySource();
    }
}
複製程式碼

注意上面的DependencyComponent,和前面不同,我們不在它裡面宣告一個inject介面,而是宣告瞭一個getDependencySource介面,返回值為DependencySource,表示可以給被它依賴的Component提供DependencySource這種型別的例項。

2.2 定義依賴 DependencyComponent 的 SourceComponent

接下來,我們建立一個SourceComponent

@Component(dependencies = DependencyComponent.class)
public interface SourceComponent {
    public void inject(DataRepository dataRepository);
}
複製程式碼

Component註解中,採用dependencies來指明它所依賴的Component,接下來,建立一個DataRepository,通過依賴注入的方式來例項化它的DependencySource成員變數,具體的操作步驟為:

  • 通過@Inject宣告需要注入的變數mDependencySource
  • 點選make編譯
  • 通過DaggerDependencyComponent例項化依賴的DependencyComponent
  • 建立DaggerSourceComponent,在構造的過程中,傳入第二步中的DependencyComponent
  • 呼叫DaggerSourceComponentinject方法完成注入
public class DataRepository {

    @Inject
    DependencySource mDependencySource;

    public DataRepository() {
        //1.例項化所依賴的Component。
        DependencyComponent dependencyComponent = DaggerDependencyComponent.create();
        //2.在構建時傳入依賴的Component例項。
        DaggerSourceComponent.builder().dependencyComponent(dependencyComponent).build().inject(this);
    }

    public String getDependencyData() {
        return mDependencySource.getData();
    }
}
複製程式碼

2.3 小結

當通過這種依賴於其它Component方式完成注入時,Dagger2會去依賴的Component中查詢它是否宣告瞭 返回值為需要例項化的類的方法,如果有,那麼就通過該Component來完成注入。

整個流程如下圖所示:

依賴方式

對於被依賴的Component,它宣告自己可以提供哪些類的例項化,但是並不知道具體有哪些Component需要依賴它。

三、使用繼承方式完成注入

3.1 定義父 Component - SourceComponent

在第二節的例子中,我們讓SourceComponent依賴於DependencyComponent,完成DependencySource的依賴注入。

下面,我們演示讓SourceComponent被其他的Component繼承,使得其他Component可以通過它來完成依賴注入,這裡唯一的不同,就是該Component需要定義一個getSubSourceComponent()來返回子Component,關於SubSourceComponent3.2中會進行介紹。

@Component(dependencies = DependencyComponent.class, modules = SourceModule.class)
public interface SourceComponent {
    public void inject(DataRepository dataRepository);
    //SubSourceComponent 為子 Component。
    SubSourceComponent getSubSourceComponent();
}
複製程式碼
@Module
public class SourceModule {

    @Provides
    LocalSource provideLocalSource() {
        return new LocalSource();
    }
}
複製程式碼
public class LocalSource {

    public String getLocalData() {
        return "獲取到本地資料";
    }
}
複製程式碼

3.2 定義子 Component - SubSourceComponent

下面,我們來定義SubSourceComponent,與之前的Component不同,在介面上,加上的是@SubComponent註解,並且不需要給它指定一個Module,因為它是通過父Component來實現例項化物件的。

@Subcomponent
public interface SubSourceComponent {
    public void inject(SubRepository subRepository);
}
複製程式碼

接下來,需要通過以下幾步來完成依賴注入:

  • 在需要注入的變數上加上@Inject標籤
  • 點選make,完成一次編譯
  • 首先例項化父SourceComponent
  • 通過在3.1SourceComponent定義的getSubSourceComponent獲取到SubSourceComponent例項。
  • 呼叫SubSourceComponentinject方法完成注入。
public class SubRepository {

    @Inject
    LocalSource mLocalSource;

    public SubRepository() {
        //1.例項化所依賴的Component。
        DependencyComponent dependencyComponent = DaggerDependencyComponent.create();
        //2.在構建時傳入依賴的Component例項。
        SourceComponent sourceComponent = DaggerSourceComponent.builder().dependencyComponent(dependencyComponent).build();
        //3.獲取SubComponent。
        SubSourceComponent subSourceComponent = sourceComponent.getSubSourceComponent();
        //4.完成依賴注入。
        subSourceComponent.inject(this);
    }

    public String getLocalData() {
        return mLocalSource.getLocalData();
    }

}
複製程式碼

3.3 小結

通過繼承方式來實現依賴注入時,父Component也就是SourceComponent需要宣告一個getXXX方法,該方法返回子Component,這個子Component需要加上@SubComponent註解,它不用自己宣告Module,而是通過與父Component關聯的Module來完成依賴注入。

整個流程圖如下所示:

繼承方式

四、例項演示

下面,我們用一段小程式來演示上面的執行結果:

public class ComponentActivity extends AppCompatActivity {

    private static final String TAG = ComponentActivity.class.getSimpleName();
    private Button mBtnGetData;
    private Button mBtnGetNetData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qualifier);

        mBtnGetData = (Button) findViewById(R.id.bt_get_data);
        mBtnGetData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DataRepository repository = new DataRepository();
                String data = repository.getDependencyData();
                Toast.makeText(ComponentActivity.this, data, Toast.LENGTH_SHORT).show();
            }
        });
        mBtnGetNetData = (Button) findViewById(R.id.bt_get_net_data);
        mBtnGetNetData.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                SubRepository repository = new SubRepository();
                String data = repository.getLocalData();
                Toast.makeText(ComponentActivity.this, data, Toast.LENGTH_SHORT).show();
            }
        });
    }
}
複製程式碼

Dagger2 知識梳理(3)   使用 dependencies 和 @SubComponent 完成依賴注入


更多文章,歡迎訪問我的 Android 知識梳理系列:

相關文章