Dagger2 學習筆記 Module使用和理解

上一篇結尾說道如果有參數的調用應該是怎麼來寫呢?

最後的報錯說明一個類的構造好函數只有一個被@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來作爲一個全局的對象來使用,保證了真正的單例




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章