Dagger2 使用詳解

標(biāo)簽: Android Dagger2


更新

伴隨著 Android Gradle 插件 2.2 版本的發(fā)布辉川,近期 android-apt 作者在官網(wǎng)發(fā)表聲明證實(shí)了后續(xù)將不會(huì)繼續(xù)維護(hù) android-apt龄广,并推薦大家使用 Android 官方插件提供的相同能力粹湃。也就是說(shuō),大約三年前推出的 android-apt 即將告別開發(fā)者灰署,退出歷史舞臺(tái)判帮,Android Gradle 插件提供了名為 annotationProcessor 的功能來(lái)完全代替 android-apt
所以新的配置信息可以更加簡(jiǎn)單溉箕,在Project的 build.gradle文件添加以下內(nèi)容:

buildscript {
    
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.5.0'//支持lambda表達(dá)式晦墙,在Dagger2中可以不用添加
    }
}

然后在Module下的build.gradle添加以下內(nèi)容:

apply plugin: 'me.tatarka.retrolambda'

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
    compile 'com.google.dagger:dagger:2.4'
    provided 'org.glassfish:javax.annotation:10.0-b28'
}

前言

Dagger2 是一款使用在Java和Android上的依賴注入的一個(gè)類庫(kù)。

配置信息

使用Android Studio 創(chuàng)建一個(gè)新的項(xiàng)目肴茄,在Project的 build.gradle文件添加以下內(nèi)容:

buildscript {
    
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.4'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

并在Module下的build.gradle添加以下內(nèi)容:

apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    apt 'com.google.dagger:dagger-compiler:2.4'
    compile 'com.google.dagger:dagger:2.4'
    provided 'org.glassfish:javax.annotation:10.0-b28'
}

這樣就基本完全了Dagger2的配置環(huán)境(順便也配置了支持lambda表達(dá)式)晌畅。

Dagger2基本使用

我們先簡(jiǎn)單地創(chuàng)建一個(gè)類:

public class Poetry {
    private String mPemo;

    // 用Inject標(biāo)記構(gòu)造函數(shù),表示用它來(lái)注入到目標(biāo)對(duì)象中去
    @Inject
    public Poetry() {
        mPemo = "生活就像海洋";
    }

    public String getPemo() {
        return mPemo;
    }
}

然后我們?cè)贛ainActivity中使用這個(gè)類:

public class MainActivity extends AppCompatActivity {

    //添加@Inject注解,表示這個(gè)mPoetry是需要注入的
    @Inject
    Poetry mPoetry;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tv_poetry);
        mTextView.setText(mPoetry.getPoems());
    }
}

但是這樣直接運(yùn)行是會(huì)出錯(cuò)的寡痰,此時(shí)這樣子在MainActivity中的mPoetry對(duì)象是無(wú)法被注入的抗楔,因?yàn)镸ainActivity不知道去哪里找到它的實(shí)例去注入生成,這時(shí)我們需要一個(gè)連接器Component拦坠,讓上面這兩個(gè)類產(chǎn)生聯(lián)系:

//用@Component表示這個(gè)接口是一個(gè)連接器连躏,能用@Component注解的只
//能是interface或者抽象類
@Component
public interface MainComponent {

    /**
     * 需要用到這個(gè)連接器的對(duì)象,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思贞滨,這個(gè)方法名可以隨意更改入热,但建議就
     * 用inject即可。
     */
    void inject(MainActivity activity);
}

先運(yùn)行一遍,AS會(huì)生成一些類勺良,再修改一下MainActivity:

public class MainActivity extends AppCompatActivity {

    //添加@Inject注解绰播,表示這個(gè)mPoetry是需要注入的
    @Inject
    Poetry mPoetry;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 使用Dagger2生成的類 生成組件進(jìn)行構(gòu)造,并注入
        DaggerMainComponent.builder()
                .build()
                .inject(this);

        initView();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tv_poetry);
        mTextView.setText(mPoetry.getPoems());
    }
}

運(yùn)行郑气,如下

運(yùn)行結(jié)果
運(yùn)行結(jié)果

上面MainActivity中的Poetry實(shí)例并不直接由MainActivity類創(chuàng)建幅垮,而是由MainActivityComponent類注入生成實(shí)例腰池。以上就是一個(gè)簡(jiǎn)單的Dagger2示例尾组。

@Module

有時(shí)候我們并不能直接在構(gòu)造函數(shù)里面添加@Inject注解,或者類中存在多個(gè)構(gòu)造函數(shù)時(shí)示弓,@Inject也只能注解其中一個(gè)構(gòu)造函數(shù)讳侨,不能注解多個(gè)構(gòu)造函數(shù),這里是會(huì)產(chǎn)生歧義性奏属,因?yàn)镈agger2無(wú)法確認(rèn)調(diào)用哪一個(gè)構(gòu)造函數(shù)來(lái)生成例的實(shí)例對(duì)象跨跨。另外一種情況是我們?cè)陧?xiàng)目中引用第三方類庫(kù)時(shí),也是無(wú)法直接在類構(gòu)造函數(shù)中添加@Inject注解的囱皿,所以我們需要用到@Module注解了勇婴。
@Module是用來(lái)生產(chǎn)實(shí)例來(lái)注入對(duì)象的,它類似一個(gè)工廠嘱腥,集中創(chuàng)建要注入的類的對(duì)象實(shí)例耕渴。下面我們引用一下Gson庫(kù)來(lái)看看@Module是怎么使用的,創(chuàng)建MainModule類:

/*
@Module注解表示這個(gè)類提供生成一些實(shí)例用于注入
 */
@Module
public class MainModule {

    /**
     * @Provides 注解表示這個(gè)方法是用來(lái)創(chuàng)建某個(gè)實(shí)例對(duì)象的齿兔,這里我們創(chuàng)建返回Gson對(duì)象
     * 方法名隨便橱脸,一般用provideXXX結(jié)構(gòu)
     * @return 返回注入對(duì)象
     */
    @Provides
    public Gson provideGson(){
        return new Gson();
    }
}

添加完這個(gè)類后,我們要與之前寫的類產(chǎn)生關(guān)聯(lián)分苇,不然誰(shuí)知道你這里提供了生成Gson實(shí)例的方法啊添诉。修改MainCompontent:

//這里表示Component會(huì)從MainModule類中拿那些用@Provides注解的方法來(lái)生成需要注入的實(shí)例
@Component(modules = MainModule.class)
public interface MainComponent {

    /**
     * 需要用到這個(gè)連接器的對(duì)象医寿,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思须眷,這個(gè)方法名可以隨意更改,但建議就
     * 用inject即可。
     */
    void inject(MainActivity activity);
}

這里多了一個(gè)依賴葡公,依賴MainModule類中的方法生成Gson實(shí)例催什,我們?cè)?code>MainActivity里注入Gson實(shí)例:

public class MainActivity extends AppCompatActivity {

    //添加@Inject注解,表示這個(gè)mPoetry是需要注入的
    @Inject
    Poetry mPoetry;

    @Inject
    Gson mGson;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 使用Dagger2生成的類 生成組件進(jìn)行構(gòu)造,并注入
        DaggerMainComponent.builder()
                .build()
                .inject(this);

        initView();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tv_poetry);
        String json = mGson.toJson(mPoetry);
        mTextView.setText(json);
    }
}

運(yùn)行,結(jié)果如下:

運(yùn)行結(jié)果
運(yùn)行結(jié)果

Component可以依賴多個(gè)Module對(duì)象,以上的構(gòu)造方法與生成方法都是無(wú)參生成實(shí)例的,如果我們帶參數(shù)應(yīng)該怎么做了权她?我們創(chuàng)建多一個(gè)PoetryModule用于提供Poetry實(shí)例:

@Module
public class PoetryModule {

    // 這個(gè)方法需要一個(gè)String參數(shù),在Dagger2注入中,這些參數(shù)也是注入形式的,也就是
    // 要有其他對(duì)方提供參數(shù)poems的生成,不然會(huì)造成編譯出錯(cuò)
    @Provides
    public Poetry providePoetry(String poems){
        return new Poetry(poems);
    }
    
    // 這里提供了一個(gè)生成String的方法第步,在這個(gè)Module里生成Poetry實(shí)例時(shí),會(huì)查找到這里
    // 可以為上面提供String類型的參數(shù)
    @Provides
    public String providePoems(){
        return "只有意志堅(jiān)強(qiáng)的人樊展,才能到達(dá)彼岸";
    }
}

修改MainComponent依賴:

//這里表示Component會(huì)從MainModule類中拿那些用@Provides注解的方法來(lái)生成需要注入的實(shí)例
@Component(modules = {MainModule.class,PoetryModule.class})
public interface MainComponent {

    /**
     * 需要用到這個(gè)連接器的對(duì)象,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思太闺,這個(gè)方法名可以隨意更改蟀淮,但建議就
     * 用inject即可。
     */
    void inject(MainActivity activity);
}

運(yùn)行,就可以看到不同的詩(shī)詞了:

運(yùn)行結(jié)果
運(yùn)行結(jié)果

細(xì)心的同學(xué)就會(huì)發(fā)現(xiàn)了,我們提供了兩個(gè)可以生成Poetry實(shí)例的方法履腋,一個(gè)是在Poetry類的構(gòu)造函數(shù)時(shí)候用@Inject提供的實(shí)例創(chuàng)建方法晚吞,一個(gè)是在PoetryModule中的@Privodes注解的providePoetry方法烹卒,而在上面的運(yùn)行結(jié)果中我們發(fā)現(xiàn)是調(diào)用了PoetryModule提供的方法,這里就要說(shuō)明一下優(yōu)先級(jí)的問題,在上面這種既在構(gòu)造函數(shù)中用@Inject提供注入來(lái)源,也在@Module中用@Privodes注解提供注入來(lái)源的,Dagger2是先從@Privodes查找類實(shí)例,如果找到了就用@Module提供的方法來(lái)創(chuàng)建類實(shí)例,如果沒有就從構(gòu)造函數(shù)里用@Inject注解的生成類實(shí)例,如果二者都沒有,則報(bào)錯(cuò),簡(jiǎn)而言之旬盯,就是@Module的優(yōu)先級(jí)高于@Inject萨咳。
另外這里還要說(shuō)明一點(diǎn)鹃两,在providePoetry(String)方法中馋记,String這個(gè)參數(shù)也是要注入提供的腌紧,必須也要有在同一個(gè)連接器里面有提供,其中在構(gòu)建類實(shí)例的時(shí)候乙帮,會(huì)按照以下順序執(zhí)行:

  1. 從Module中查找類實(shí)例創(chuàng)建方法
  2. Module中存在創(chuàng)建方法盼樟,則看此創(chuàng)建方法有沒有參數(shù)
    1. 如果有參數(shù),這些參數(shù)也是由Component提供的,返回步驟1逐一生成參數(shù)類實(shí)例械拍,最后再生成最終類實(shí)例
    2. 如果無(wú)參數(shù)定躏,則直接由這個(gè)方法生成最終類實(shí)例
  3. Module中沒有創(chuàng)建方法绑谣,則從構(gòu)造函數(shù)里面找那個(gè)用@Inject注解的構(gòu)造函數(shù)
    1. 如果該構(gòu)造函數(shù)有參數(shù),則也是返回到步驟1逐一生成參數(shù)類實(shí)例拗引,最后調(diào)用該構(gòu)造函數(shù)生成類實(shí)例
    2. 如果該構(gòu)造函數(shù)無(wú)參數(shù)借宵,則直接調(diào)用該構(gòu)造函數(shù)生成類實(shí)例

以上就是一次注入生成類實(shí)例的生成步驟。

@Scope

我們創(chuàng)建多一個(gè)Activity矾削,這個(gè)Activity也注入了Poetry跟Gson對(duì)象:

public class OtherActivity extends AppCompatActivity {

    //添加@Inject注解壤玫,表示這個(gè)mPoetry是需要注入的
    @Inject
    Poetry mPoetry;

    @Inject
    Gson mGson;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);

        MainComponent.getInstance()
                .inject(this);

        initView();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tv_poetry);
        String json = mGson.toJson(mPoetry);
        String text = json + ",mPoetry:"+mPoetry;
        mTextView.setText(text);
    }
}

我們順便也把MainComponent改成抽象類的形式,并添加返回MainComponent單例的方法,對(duì)應(yīng)添加MainActivity跳轉(zhuǎn)到OtherActivity的方法.

@Component(modules = {MainModule.class,PoetryModule.class})
public abstract class MainComponent {

    /**
     * 需要用到這個(gè)連接器的對(duì)象哼凯,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思欲间,這個(gè)方法名可以隨意更改,但建議就
     * 用inject即可断部。
     */
    abstract void inject(MainActivity activity);

    abstract void inject(OtherActivity activity);

    private static MainComponent sComponent;
    public static MainComponent getInstance(){
        if (sComponent == null){
            sComponent = DaggerMainComponent.builder().build();
        }
        return sComponent;
    }
}

public class MainActivity extends AppCompatActivity {

    //添加@Inject注解猎贴,表示這個(gè)mPoetry是需要注入的
    @Inject
    Poetry mPoetry;

    @Inject
    Gson mGson;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 使用Dagger2生成的類 生成組件進(jìn)行構(gòu)造,并注入
        MainComponent.getInstance()
                .inject(this);

        initView();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tv_poetry);
        String json = mGson.toJson(mPoetry);
        String text = json + ",mPoetry:"+mPoetry;
        mTextView.setText(text);

        findViewById(R.id.open).setOnClickListener(view ->
                startActivity(new Intent(this,OtherActivity.class)));
    }
}

運(yùn)行結(jié)果如下:

運(yùn)行結(jié)果
運(yùn)行結(jié)果
運(yùn)行結(jié)果
運(yùn)行結(jié)果

可以看到蝴光,調(diào)用同一個(gè)MainComponent實(shí)例多次注入的時(shí)候每次都重新生成Poetry實(shí)例她渴,有時(shí)候我們需要只希望生成一個(gè)共用實(shí)例的時(shí)候應(yīng)該怎么辦呢,這里我們就需要用到Dagger2的@Scope屬性了蔑祟,Scope是作用域的意思趁耗,我們先自定義一個(gè)@Scope注解:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PoetryScope {
}

同時(shí)在Module與Component加上這個(gè)自定義Scope:

@PoetryScope
@Component(modules = {MainModule.class,PoetryModule.class})
public abstract class MainComponent {
    /**
     * 需要用到這個(gè)連接器的對(duì)象,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思疆虚,這個(gè)方法名可以隨意更改苛败,但建議就
     * 用inject即可。
     */
    abstract void inject(MainActivity activity);

    abstract void inject(OtherActivity activity);

    private static MainComponent sComponent;
    public static MainComponent getInstance(){
        if (sComponent == null){
            sComponent = DaggerMainComponent.builder().build();
        }
        return sComponent;
    }
}

@Module
public class PoetryModule {

    // 這個(gè)方法需要一個(gè)String參數(shù)径簿,在Dagger2注入中罢屈,這些參數(shù)也是注入形式的,也就是
    // 要有其他對(duì)方提供參數(shù)poems的生成牍帚,不然會(huì)造成編譯出錯(cuò)
    @PoetryScope
    @Provides
    public Poetry providePoetry(String poems){
        return new Poetry(poems);
    }

    // 這里提供了一個(gè)生成String的方法儡遮,在這個(gè)Module里生成Poetry實(shí)例時(shí),會(huì)查找到這里
    // 可以為上面提供String類型的參數(shù)
    @Provides
    public String providePoems(){
        return "只有意志堅(jiān)強(qiáng)的人暗赶,才能到達(dá)彼岸";
    }
}

重新運(yùn)行:


運(yùn)行結(jié)果
運(yùn)行結(jié)果
運(yùn)行結(jié)果
運(yùn)行結(jié)果

這時(shí)你會(huì)發(fā)現(xiàn)這兩個(gè)Poetry實(shí)例是同一個(gè)實(shí)例來(lái)的鄙币,通過實(shí)現(xiàn)自定義@Scope注解肃叶,標(biāo)記當(dāng)前生成對(duì)象的使用范圍,標(biāo)識(shí)一個(gè)類型的注射器只實(shí)例化一次十嘿,在同一個(gè)作用域內(nèi)因惭,只會(huì)生成一個(gè)實(shí)例,然后在此作用域內(nèi)共用一個(gè)實(shí)例绩衷。這樣看起來(lái)很像單例模式蹦魔,我們可以查看@Singleton其實(shí)就是@Scope的一個(gè)默認(rèn)實(shí)現(xiàn)而已。當(dāng)然咳燕,你得是同一個(gè)Component對(duì)象來(lái)生成勿决,這點(diǎn)我們應(yīng)該可以理解的吧。
我們可以通過自定義Scope來(lái)組織Component的作用域招盲,使得每個(gè)Component的作用域清晰明了低缩,各施其職。

組織Component

我們?cè)谝粋€(gè)項(xiàng)目之中不可能只使用一個(gè)Component連接器來(lái)注入對(duì)象完成注入工作曹货,一般除了一個(gè)全局的ApplicationComponent之外咆繁,還有一些作用域在Activity/Fragment的Component,Component之間存在依賴關(guān)系與從屬關(guān)系顶籽。如果我們已經(jīng)創(chuàng)建好了一個(gè)全局的ApplicationComponent玩般,然后其它的Component剛好需要ApplicationComponent里面的一個(gè)全局屬性,想要與ApplicationComponent共享同一個(gè)實(shí)例礼饱,這時(shí)就需要用到依賴關(guān)系了坏为。

依賴方式

一個(gè)Component可以依賴一個(gè)或多個(gè)Component,并拿到被依賴Component暴露出來(lái)的實(shí)例慨仿,Component的dependencies屬性就是確定依賴關(guān)系的實(shí)現(xiàn)久脯。
這里的有點(diǎn)像數(shù)學(xué)里面的交集方式,被依賴的Component主動(dòng)暴露對(duì)象給二者共享镰吆,如我們?cè)贏pplicationModule提供了一個(gè)全局的Gson對(duì)象,我們想要提供給其他Component時(shí)跑慕,要在ApplicationComponent顯式的提供一個(gè)接口:

@Module
public class ApplicationModule {

    /**
     * @Provides 注解表示這個(gè)方法是用來(lái)創(chuàng)建某個(gè)實(shí)例對(duì)象的万皿,這里我們創(chuàng)建返回Gson對(duì)象
     * 方法名隨便,一般用provideXXX結(jié)構(gòu)
     * @return 返回注入對(duì)象
     */
    @Singleton
    @Provides
    public Gson provideGson(){
        return new Gson();
    }
}

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    Gson getGson();// 暴露Gson對(duì)象接口
}

并在自定義的MainApplication中初始化它核行,更改MainComponent:

public class MainApplication extends Application {

    private ApplicationComponent mApplicationComponent;
    private static MainApplication sApplication;

    public static MainApplication getInstance() {
        return sApplication;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;

        mApplicationComponent = DaggerApplicationComponent.builder().build();
    }

    public ApplicationComponent getApplicationComponent() {
        return mApplicationComponent;
    }
}

//這里表示Component會(huì)從MainModule類中拿那些用@Provides注解的方法來(lái)生成需要注入的實(shí)例
@PoetryScope
@Component(dependencies = ApplicationComponent.class, modules = {MainModule.class,PoetryModule.class})
public abstract class MainComponent {

    /**
     * 需要用到這個(gè)連接器的對(duì)象牢硅,就是這個(gè)對(duì)象里面有需要注入的屬性
     * (被標(biāo)記為@Inject的屬性)
     * 這里inject表示注入的意思,這個(gè)方法名可以隨意更改芝雪,但建議就
     * 用inject即可减余。
     */
    abstract void inject(MainActivity activity);

    abstract void inject(OtherActivity activity);

    private static MainComponent sComponent;
    public static MainComponent getInstance(){
        if (sComponent == null){
            sComponent = DaggerMainComponent.builder()
                    .applicationComponent(MainApplication.getInstance()
                    .getApplicationComponent())
                    .build();
        }
        return sComponent;
    }
}

這樣就達(dá)到了MainComponent依賴ApplicationComponent。并且這里需要注意的是惩系,MainComponent的作用域不能和ApplicationComponent的作用域一樣位岔,否則會(huì)報(bào)錯(cuò)如筛,一般來(lái)講,我們應(yīng)該對(duì)每個(gè)Component都定義不同的作用域抒抬。

包含方式(從屬方式)@SubComponent

如果我們需要父組件全部的提供對(duì)象杨刨,這時(shí)我們可以用包含方式而不是用依賴方式,相比于依賴方式擦剑,包含方式不需要父組件顯式顯露對(duì)象妖胀,就可以拿到父組件全部對(duì)象。且SubComponent只需要在父Component接口中聲明就可以了惠勒。添加多一個(gè)AActivity,AComponent:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface AScope {
}

@Module
public class AModule {

    @AScope
    @Provides
    public Poetry getPoetry(){
        return new Poetry("萬(wàn)物美好");
    }
}

@AScope
@Subcomponent(modules = AModule.class)
public interface AComponent {
    void inject(AActivity activity);
}

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    Gson getGson();// 暴露Gson對(duì)象接口

    //AComponent plus();
    AComponent plus(AModule module);//添加聲明
}


public class MainApplication extends Application {

    private ApplicationComponent mApplicationComponent;
    private AComponent mAComponent;
    private static MainApplication sApplication;

    public static MainApplication getInstance() {
        return sApplication;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;

        mApplicationComponent = DaggerApplicationComponent.builder().build();
    }

    public ApplicationComponent getApplicationComponent() {
        return mApplicationComponent;
    }

    public AComponent getAComponent() {
        if (mAComponent == null){
            mAComponent = mApplicationComponent.plus(new AModule());
        }
        return mAComponent;
    }
}

public class AActivity extends AppCompatActivity {
    TextView mTextView;

    @Inject
    Gson mGson;

    @Inject
    Poetry mPoetry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);

        MainApplication.getInstance()
                .getAComponent()
                .inject(this);

        mTextView = (TextView) findViewById(R.id.text);
        String text = mPoetry.getPoems()+",mPoetry:"+mPoetry+(mGson == null ? "Gson沒被注入" : "Gson已經(jīng)被注入");
        mTextView.setText(text);
    }
}

最后我們?cè)贠therActivity中添加一個(gè)按鈕跳轉(zhuǎn)到AActivity赚抡,運(yùn)行結(jié)果如下:


運(yùn)行結(jié)果
運(yùn)行結(jié)果

@Qualifier

假如在上面的AActivity里面我們想要注入兩個(gè)不同的Poetry(指peoms不一樣)實(shí)例,我們可以在AModule下添加多一個(gè)生成Poetry的方法:

@Module
public class AModule {

    @AScope
    @Provides
    public Poetry getPoetry(){
        return new Poetry("萬(wàn)物美好");
    }
    
    @AScope
    @Provides
    public Poetry getOtherPoetry(){
        return new Poetry("我在中間");
    }
}

但是直接這樣做Dagger2是無(wú)法區(qū)分調(diào)用哪個(gè)方法生成Poetry實(shí)例的纠屋,這個(gè)時(shí)候就需要自定義@Qualifier限定符來(lái)匹配注入方法了涂臣,添加一個(gè)自定義Qualifier并修AMoudule,AActivity:

@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PoetryQualifier {
    String value() default "";
}

@Module
public class AModule {

    @PoetryQualifier("A")
    @AScope
    @Provides
    public Poetry getPoetry(){
        return new Poetry("萬(wàn)物美好");
    }

    @PoetryQualifier("B")
    @AScope
    @Provides
    public Poetry getOtherPoetry(){
        return new Poetry("我在中間");
    }
}

public class AActivity extends AppCompatActivity {
    TextView mTextView;

    @Inject
    Gson mGson;

    // 匹配Module中同樣注解的方法
    @PoetryQualifier("A")
    @Inject
    Poetry mPoetry;
    
    // 匹配Module中同樣注解的方法
    @PoetryQualifier("B")
    @Inject
    Poetry mPoetryB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);

        MainApplication.getInstance()
                .getAComponent()
                .inject(this);

        mTextView = (TextView) findViewById(R.id.text);
        String text = mPoetry.getPoems()+",mPoetryA:"+mPoetry+
                mPoetryB.getPoems()+",mPoetryB:"+mPoetryB+
                (mGson == null ? "Gson沒被注入" : "Gson已經(jīng)被注入");
        mTextView.setText(text);
    }
}

重新編譯運(yùn)行:


運(yùn)行結(jié)果
運(yùn)行結(jié)果

而Dagger2已經(jīng)默認(rèn)幫我們實(shí)現(xiàn)了一個(gè)@Named:

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

跟我們自定義的PoetryQualifier其實(shí)是一樣的巾遭。

后記

這篇是我參考了其他文章之后自己又重新總結(jié)一遍的肉康,錯(cuò)誤之處請(qǐng)幫忙指出,大家一起進(jìn)步灼舍。除了以上常用到的注解之外吼和,Dagger還提供了其他一些注解,如Set骑素,Map類的注解炫乓,具體可以參考以下文章。

參考

Dagger2圖文完全教程
Google官方MVP+Dagger2架構(gòu)詳解【從零開始搭建android框架系列(6)】
Android:dagger2讓你愛不釋手-基礎(chǔ)依賴注入框架篇
Android:dagger2讓你愛不釋手-重點(diǎn)概念講解献丑、融合篇
Android:dagger2讓你愛不釋手-終結(jié)篇
Android:Dagger2學(xué)習(xí)之由淺入深

Demo地址

https://github.com/EvilBT/-Dagger2Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末末捣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子创橄,更是在濱河造成了極大的恐慌箩做,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妥畏,死亡現(xiàn)場(chǎng)離奇詭異邦邦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)醉蚁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門燃辖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人网棍,你說(shuō)我怎么就攤上這事黔龟。” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵氏身,是天一觀的道長(zhǎng)巍棱。 經(jīng)常有香客問我,道長(zhǎng)观谦,這世上最難降的妖魔是什么拉盾? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮豁状,結(jié)果婚禮上捉偏,老公的妹妹穿的比我還像新娘。我一直安慰自己泻红,他們只是感情好夭禽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谊路,像睡著了一般讹躯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缠劝,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天潮梯,我揣著相機(jī)與錄音,去河邊找鬼惨恭。 笑死秉馏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脱羡。 我是一名探鬼主播萝究,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锉罐!你這毒婦竟也來(lái)了帆竹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脓规,失蹤者是張志新(化名)和其女友劉穎栽连,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侨舆,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡升酣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了态罪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡下面,死狀恐怖复颈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤耗啦,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布凿菩,位于F島的核電站,受9級(jí)特大地震影響帜讲,放射性物質(zhì)發(fā)生泄漏衅谷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一似将、第九天 我趴在偏房一處隱蔽的房頂上張望获黔。 院中可真熱鬧,春花似錦在验、人聲如沸玷氏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盏触。三九已至,卻和暖如春块饺,著一層夾襖步出監(jiān)牢的瞬間赞辩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工授艰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辨嗽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓想诅,卻偏偏與公主長(zhǎng)得像召庞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子来破,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容