Dagger2 知識梳理(2) @Qulifier 和 @Named 解決依賴注入迷失

1、前言

Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中,咱們提到了兩種實現依賴注入的方法:java

  • 在依賴類的構造函數上增長@Inject註解
  • 提供一個Module類,在其中建立提供依賴類實例的方法

在使用第二種方法時,Dagger2 在尋找目標依賴類的建立方法時,是根據 Module 提供的方法的返回類型來肯定的,所以若是咱們提供了多個返回類型相同的建立方法時,那麼Dagger2就沒法判斷使用哪一個函數來建立實例,將會在編譯時拋出異常。對於這種狀況,咱們稱爲 依賴注入迷失git

對於這種狀況,咱們能夠經過@Qualifier/@Named註解來解決,這篇文章的完整代碼能夠從 Dagger2Sample 的第二章獲取。github

2、示例

咱們仍是像 Dagger2 知識梳理(1) - Dagger2 依賴注入的兩種方式 中介紹的同樣,採用一個數據倉庫DataReposity做爲例子,它內部包含兩個數據源,分別爲LocalSourceRemoteSource,而這兩個類都實現了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

(1) 目標類的成員變量

(2) Module 中提供的建立方法

最後,咱們用一個例子演示最終的效果:

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();
            }
        });
    }
}
複製代碼

運行結果:

3、使用 @Named

上面咱們使用的是@Qulifier註解來實現,@Named也能夠達到相同的效果。仍是用上面的例子,咱們不須要從新定義兩個註解@Local@Remote,而是直接在須要加上別名的兩個地方,添加@Named("Local")@Named("Remote"),也就是將@Named後面括號中的字符串做爲關聯目標類型的成員變量和建立方法之間的別名。

(1) 目標類的成員變量

(2) Module 中提供的建立方法


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

相關文章
相關標籤/搜索