上一篇結尾說道如果有參數的調用應該是怎麼來寫呢?
最後的報錯說明一個類的構造好函數只有一個被@Inject標註
前面說過
@Module:@Module用於封裝提供依賴的類。爲什麼需要專門提供這個註解,因爲在很多情況下,我們需要注入的類是第三方類庫,我們無法再構造函數直接加@Inject註解,還有一個問題就是如果有多個構造函數的問題,Module封裝依賴就是爲了解決這些問題。
這裏我們就需要使用Module了,首先我們先看下如果是第三方庫類的注入
@Module
public class DateModule {
int mid;
public DateModule(int id) {
mid = id;
}
@Provides
public Phone providePhone(){
return new Phone(mid);//這裏假設Phone是第三方庫裏面的類
}
@Provides
public Book provideBook(){
return new Book(mid);//這裏假設Book是第三方庫裏面的類
}
}
這裏新建一個DataModule類用@Module標註
他有兩個方法providePhone和provideBook都用@Provides標註,然後接下來還需要一個步驟繼續看BookComponent
@Component(modules = {DateModule.class})
public interface BookComponent {
void inject(MainActivity activity);
}
這裏@Component加了參數modules參數,可以表明對外提供的是那個Module,這裏可以寫多個Module
下面我們就看下調用方式
public class MainActivity extends AppCompatActivity {
@Inject
Book mBook;
@Inject
Phone mPhone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBookComponent.builder()
.dateModule(new DateModule(0))
.build()
.inject(this);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("wangyudong", "mBook: " + mBook.toString());
Log.e("wangyudong", "mPhone: " + mPhone.toString());
}
});
}
}
可以看出來區別就在於這裏的DaggerBookComponent的Builder需要傳入一個DateModule作爲參數,來初始化Dagger
到這裏就可以完成第三方類的注入了
2.第二個問題,如果有多個構造器呢?
這裏就需要用到一個新的註解
@Qulifier:@Qulifier用於自定義註解,也就是說@Qulifier就如同Java提供的幾種基本元註解一樣用來標記註解類。我們在使用@Module來標註提供依賴的方法時,方法名我們是可以隨便定義的(雖然我們定義方法名一般以provide開頭,但這並不是強制的,只是爲了增加可讀性而已)。那麼Dagger2怎麼知道這個方法是爲誰提供依賴呢?答案就是返回值的類型,Dagger2根據返回值的類型來決定爲哪個被@Inject標記了的變量賦值。但是問題來了,一旦有多個一樣的返回類型Dagger2就懵逼了。@Qulifier的存在正式爲了解決這個問題,我們使用@Qulifier來定義自己的註解,然後通過自定義的註解去標註提供依賴的方法和依賴需求方(也就是被@Inject標註的變量),這樣Dagger2就知道爲誰提供依賴了。----一個更爲精簡的定義:當類型不足以鑑別一個依賴的時候,我們就可以使用這個註解標示;
一句話這個註解是一個原註解,用來生成自定義註解,因爲Dagger解析的時候是通過@provide的返回值來匹配的,如果有多個函數返回值一樣,dagger就不知道該用那個來生成實例了,因此用不同的自定義註解,把相同返回值類型的方法區別開來
正式用一下,自定義兩個註解
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifierC1 {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BookQualifierC2 {
}
使用自定義註解
@Module
public class DateModule {
int mid;
String mName;
public DateModule(int id, String name) {
mid = id;
mName = name;
}
@Provides
public Phone providePhone(){
return new Phone(mid);
}
@BookQualifierC1
@Provides
public Book provideBookC1(){
return new Book(mid);
}
@BookQualifierC2
@Provides
public Book provideBookC2(){
return new Book(mid, mName);
}
}
用自定義註解標記變量
public class MainActivity extends AppCompatActivity {
@BookQualifierC2 @Inject Book mBook;
@Inject
Phone mPhone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBookComponent.builder()
.dateModule(new DateModule(0, "哈利波特"))
.build()
.inject(this);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("wangyudong", "mBook: " + mBook.mName);
Log.e("wangyudong", "mPhone: " + mPhone.toString());
}
});
}
}
這樣就mBook的實例就是通過調用兩個參數的構造函數來獲取的
到此就基本可以滿足大多數的對象的注入了
3.最後 還有兩個註解@Scope和@SingleTon
Scope中文意思範圍的意思,我能可以通過@Scope自定義的註解來限定註解作用域,實現局部的單例;
@Singleton 其實就是一個通過@Scope定義的註解,我們一般通過它來實現全局單例。但實際上它並不能提前全局單例,是否能提供全局單例還要取決於對應的Component是否爲一個全局對象。一般都是通過在Application裏面通過Builder產品Daggerxxx類,然後其他地方都調用這個Component來作爲一個全局的對象來使用,保證了真正的單例