在 Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中,咱們提到了兩種實現依賴注入的方法:java
@Inject
註解Module
類,在其中建立提供依賴類實例的方法在使用第二種方法時,Dagger2 在尋找目標依賴類的建立方法時,是根據 Module 提供的方法的返回類型來肯定的,所以若是咱們提供了多個返回類型相同的建立方法時,那麼Dagger2
就沒法判斷使用哪一個函數來建立實例,將會在編譯時拋出異常。對於這種狀況,咱們稱爲 依賴注入迷失。git
對於這種狀況,咱們能夠經過@Qualifier/@Named
註解來解決,這篇文章的完整代碼能夠從 Dagger2Sample 的第二章獲取。github
咱們仍是像 Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中介紹的同樣,採用一個數據倉庫DataReposity
做爲例子,它內部包含兩個數據源,分別爲LocalSource
和RemoteSource
,而這兩個類都實現了Source
接口,SourceModule
用於提供這兩個數據源,而SourceComponent
則做爲注入器。網絡
public class LocalSource implements Source {
@Override
public String getData() {
return "讀取本地數據成功";
}
}
複製代碼
public class RemoteSource implements Source {
@Override
public String getData() {
return "讀取網絡數據成功";
}
}
複製代碼
SourceComponent
:@Component(modules = SourceModule.class)
public interface SourceComponent {
public void inject(DataRepository dataRepository);
}
複製代碼
@Module
public class SourceModule {
@Provides
public Source provideLocalSource() {
return new LocalSource();
}
@Provides
public Source providerRemoteSource() {
return new RemoteSource();
}
}
複製代碼
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();
}
}
複製代碼
這裏所採用的就是咱們在第一節中介紹的第二種依賴注入的方式,可是若是咱們這時候點擊make
,那麼會曝出下面的錯誤:ide
這是由於Dagger2
在尋找mLocalSource
的建立方法時,它會去Component
關聯的Module
中(也就是SourceModule
)尋找返回類型爲Source
的方法,可是在SourceModule
中,provideLocalSource / providerRemoteSource
這兩個方法返回的類型都爲SourceModule
,致使沒法肯定使用哪一個方法來建立mLocalSource
。函數
這時候就須要咱們提供一個別名,讓 目標類成員變量的類型 和 建立方法的返回類型 造成一對一的關係,通常來講,使用@Qulifier
是比較標準的方式。this
咱們先利用@Qulifier
建立兩個別名,分別對應本地和遠程數據源:spa
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Local {}
複製代碼
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Remote {}
複製代碼
接下來,爲了創建惟一關係,咱們須要在兩個地方加上這個別名:code
Module
中建立目標類的成員變量的方法即下面的兩個截圖中紅色框部分: cdn
最後,咱們用一個例子演示最終的效果:
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();
}
});
}
}
複製代碼
運行結果:
上面咱們使用的是@Qulifier
註解來實現,@Named
也能夠達到相同的效果。仍是用上面的例子,咱們不須要從新定義兩個註解@Local
和@Remote
,而是直接在須要加上別名的兩個地方,添加@Named("Local")
和@Named("Remote")
,也就是將@Named
後面括號中的字符串做爲關聯目標類型的成員變量和建立方法之間的別名。