一、前言
在 Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中,我們介紹了兩種依賴注入的方式,其中第二種是通過給注入器Component
指定Module
,再由Module
提供建立例項的方法,來實現依賴注入,這是一種“自給自足”的方式,在這種情況下,我們的Component
是這麼宣告的:
Component
可以通過其他的Component
完成依賴注入,可以劃分為:依賴方式 和 繼承方式。
- 通過依賴方式實現時,需要在
Component
中指定它所依賴的Component
名字: 而被依賴的Component
需要宣告它可以提供哪些類的例項化,因此它需要在Component
中宣告一些返回值為這些類的方法: - 通過繼承方式時實現時,子
Component
類需要用@SubComponent
宣告,這種情況下,它一般類似於下面這樣: 並且我們不能直接建立該Component
的例項來完成依賴注入,而是需要由父Component
例項提供一個getXXX
來將這個SubComponent
返回給使用者,SubComponent
自動擁有了父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
- 呼叫
DaggerSourceComponent
的inject
方法完成注入
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
,關於SubSourceComponent
在3.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.1
中SourceComponent
定義的getSubSourceComponent
獲取到SubSourceComponent
例項。 - 呼叫
SubSourceComponent
的inject
方法完成注入。
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();
}
});
}
}
複製程式碼
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:www.jianshu.com/p/fd82d1899…
- 個人主頁:lizejun.cn
- 個人知識總結目錄:lizejun.cn/categories/