Dagger2 系列文章
Dagger2 知識(shí)梳理(1) - Dagger2 依賴注入的兩種方式
Dagger2 知識(shí)梳理(2) - @Qulifier 和 @Named 解決依賴注入迷失
Dagger2 知識(shí)梳理(3) - 使用 dependencies 和 @SubComponent 完成依賴注入
Dagger2 知識(shí)梳理(4) - @Scope 注解的使用
一、前言
在 Dagger2 知識(shí)梳理(1) - Dagger2 依賴注入的兩種方式 中,我們提到了兩種實(shí)現(xiàn)依賴注入的方法:
- 在依賴類的構(gòu)造函數(shù)上增加
@Inject
注解 - 提供一個(gè)
Module
類,在其中創(chuàng)建提供依賴類實(shí)例的方法
在使用第二種方法時(shí),Dagger2 在尋找目標(biāo)依賴類的創(chuàng)建方法時(shí),是根據(jù) Module 提供的方法的返回類型來(lái)確定的,因此如果我們提供了多個(gè)返回類型相同的創(chuàng)建方法時(shí),那么Dagger2
就無(wú)法判斷使用哪個(gè)函數(shù)來(lái)創(chuàng)建實(shí)例,將會(huì)在編譯時(shí)拋出異常。對(duì)于這種情況,我們稱為 依賴注入迷失。
對(duì)于這種情況,我們可以通過(guò)@Qualifier/@Named
注解來(lái)解決,這篇文章的完整代碼可以從 Dagger2Sample 的第二章獲取。
二、示例
我們還是像 Dagger2 知識(shí)梳理(1) - Dagger2 依賴注入的兩種方式 中介紹的一樣,采用一個(gè)數(shù)據(jù)倉(cāng)庫(kù)DataReposity
作為例子,它內(nèi)部包含兩個(gè)數(shù)據(jù)源,分別為LocalSource
和RemoteSource
,而這兩個(gè)類都實(shí)現(xiàn)了Source
接口,SourceModule
用于提供這兩個(gè)數(shù)據(jù)源,而SourceComponent
則作為注入器。
- 本地?cái)?shù)據(jù)源
public class LocalSource implements Source {
@Override
public String getData() {
return "讀取本地?cái)?shù)據(jù)成功";
}
}
- 網(wǎng)絡(luò)數(shù)據(jù)源
public class RemoteSource implements Source {
@Override
public String getData() {
return "讀取網(wǎng)絡(luò)數(shù)據(jù)成功";
}
}
- 依賴注入接口,
SourceComponent
:
@Component(modules = SourceModule.class)
public interface SourceComponent {
public void inject(DataRepository dataRepository);
}
- 創(chuàng)建工廠類
@Module
public class SourceModule {
@Provides
public Source provideLocalSource() {
return new LocalSource();
}
@Provides
public Source providerRemoteSource() {
return new RemoteSource();
}
}
- 注入目標(biāo)類
public class DataRepository {
@Inject
Source mLocalSource;
@Inject
Source mRemoteSource;
public DataRepository() {
DaggerSourceComponent.create().inject(this);
}
public String getLocalData() {
return mLocalSource.getData();
}
public String getRemoteData() {
return mRemoteSource.getData();
}
}
這里所采用的就是我們?cè)诘谝还?jié)中介紹的第二種依賴注入的方式,但是如果我們這時(shí)候點(diǎn)擊make
,那么會(huì)曝出下面的錯(cuò)誤:
這是因?yàn)?code>Dagger2在尋找mLocalSource
的創(chuàng)建方法時(shí),它會(huì)去Component
關(guān)聯(lián)的Module
中(也就是SourceModule
)尋找返回類型為Source
的方法,但是在SourceModule
中,provideLocalSource / providerRemoteSource
這兩個(gè)方法返回的類型都為SourceModule
,導(dǎo)致無(wú)法確定使用哪個(gè)方法來(lái)創(chuàng)建mLocalSource
。
這時(shí)候就需要我們提供一個(gè)別名,讓 目標(biāo)類成員變量的類型 和 創(chuàng)建方法的返回類型 形成一對(duì)一的關(guān)系,一般來(lái)說(shuō),使用@Qulifier
是比較標(biāo)準(zhǔn)的方式。
我們先利用@Qulifier
創(chuàng)建兩個(gè)別名,分別對(duì)應(yīng)本地和遠(yuǎn)程數(shù)據(jù)源:
- 本地?cái)?shù)據(jù)源別名
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Local {}
- 網(wǎng)絡(luò)數(shù)據(jù)源別名
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Remote {}
接下來(lái),為了建立唯一關(guān)系,我們需要在兩個(gè)地方加上這個(gè)別名:
- 目標(biāo)類的成員變量
- 工廠
Module
中創(chuàng)建目標(biāo)類的成員變量的方法
即下面的兩個(gè)截圖中紅色框部分:
最后,我們用一個(gè)例子演示最終的效果:
public class QualifierActivity extends AppCompatActivity {
private static final String TAG = QualifierActivity.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.getLocalData();
Toast.makeText(QualifierActivity.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) {
DataRepository repository = new DataRepository();
String data = repository.getRemoteData();
Toast.makeText(QualifierActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
}
}
運(yùn)行結(jié)果:
三、使用 @Named
上面我們使用的是@Qulifier
注解來(lái)實(shí)現(xiàn),@Named
也可以達(dá)到相同的效果。還是用上面的例子,我們不需要重新定義兩個(gè)注解@Local
和@Remote
,而是直接在需要加上別名的兩個(gè)地方,添加@Named("Local")
和@Named("Remote")
,也就是將@Named
后面括號(hào)中的字符串作為關(guān)聯(lián)目標(biāo)類型的成員變量和創(chuàng)建方法之間的別名。
更多文章,歡迎訪問(wèn)我的 Android 知識(shí)梳理系列:
- Android 知識(shí)梳理目錄:http://www.lxweimin.com/p/fd82d18994ce
- 個(gè)人主頁(yè):http://lizejun.cn
- 個(gè)人知識(shí)總結(jié)目錄:http://lizejun.cn/categories/