Dagger2 入門有這篇就夠了(晉級(jí)篇)

Dagger2 入門晉級(jí)篇,直奔主題吧复濒!

一 :組件之間的依賴

  1. MainActivityModule 中Schoole的提供方法把敞,需要參數(shù)Principal 的實(shí)例,但是MainActivityModule 蛤克,中并沒有提供捺癞。可是AppComponent對(duì)應(yīng)的AppModule有提供构挤。于是我們讓MainComponent依賴AppComponent髓介,并在AppComponent中將Principal 實(shí)例提供出來。另外注入的時(shí)候也略有不同儿倒,具體看代碼(提示:這些代碼在Demo中的simplemvpmedo 的Module中哦)
@(個(gè)人博客)Module
public class MainActivityModule {
    private MainActivity mMainActivity;

    public MainActivityModule(MainActivity activity) {

        this.mMainActivity = activity;
    }
    //貨架
    @Provides
    public MainActivity provideMainActivity() {
        return mMainActivity;//貨架提供的商品
    }
    @Provides
    public Schoole provideSchoole(Principal principal) {
        return new Schoole(principal);
    }

}

MainActivityModule 相對(duì)應(yīng)的MainComponent 版保,該MainComponent 依賴了AppComponent。然后我們?cè)诳聪翧ppComponentded

/**
 * Created by zyg on 2016/11/8.
 * 供貨商夫否,交易商
 */
@Component(dependencies = AppComponent.class ,modules = MainActivityModule.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);//簽訂合同,必須用MainActivity(采購商)叫胁,接收凰慈。它老爸都不行哦
}
  • AppComponent 作為被依賴的控件,需要向依賴它的控件提供Principal 的實(shí)例驼鹅,因?yàn)橐蕾囁慕M件MainComponent 需要Principal 的實(shí)例微谓,然后再看AppComponent 對(duì)應(yīng)的Module

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication application);
    //父組件必須把該類的實(shí)例提供給子組件
    Principal getPrincipal();
}
  • 調(diào)用的時(shí)候也有區(qū)別,還是看代碼输钩,看看注入代碼
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "daggerTest";
    @Inject
    Schoole mSchoole;
    @Inject
    Schoole mSchoole2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent.builder()
                .appComponent(getComponent())
                .mainActivityModule(new MainActivityModule(this))
                .build()
                .inject(this);

    }

    //獲取AppComponent
    private AppComponent getComponent() {
        return ((MyApplication) getApplication()).getAppComponent();
    }

    //更新UI的操作
    public void refeshUi() {

        Log.d(TAG, "更新ui");

    }
}
  • 注入的時(shí)候多了appComponent()豺型,這個(gè)方法,需要傳入AppComponent作為參數(shù)买乃,這里我們從MyApplication中獲取姻氨,看下MyApplication 的代碼
public class MyApplication extends Application {
    @Inject
    Principal mPrincipal; //校長
    @Inject
    Principal vicePrincipal;//副校長
    AppComponent appComponent;
    @Override
    public void onCreate() {

        appComponent = DaggerAppComponent
                .builder()
                .appModule(new AppModule())
                .build();
        appComponent.inject(this);
        Toast.makeText(this, mPrincipal.say(), Toast.LENGTH_SHORT).show();

    }

    public AppComponent getAppComponent() {
        return appComponent;
    }
}
總結(jié):這樣MainComponent 就從AppComponent中拿到了Principal 的實(shí)例,并傳給new Schoole方法剪验,最終完成 Schoole類的實(shí)例注入到MainActivity的任務(wù)肴焊。提醒下AppComponent,一定得把Principal 提供出去功戚,這是關(guān)鍵娶眷。

二: @SubComponent,子組件(公共組件)

  1. 如果有一個(gè)組件,是每次創(chuàng)建實(shí)例提供給別人啸臀,而恰好其他組件(有多個(gè))里面有需要它届宠,如果只有一個(gè),我們就用依賴搞定啦乘粒。多個(gè)它就可以定義成子組件豌注,誰需要在誰的組件里面加一下,具體看例子.(提示:Demo源碼中的DaggerTest的Module哦)
  • 先來定義個(gè)子組件谓厘,注解@Subcomponent.
@PerActivity
@Subcomponent(modules = ComonModule.class)
public interface CommonComponent {
    Test4 getText4();
}
  • 在看與子組件相關(guān)的Module--ComonModule 幌羞,子組件提供Test4,Test4的代碼就不貼了,在Demo中看吧竟稳。
@Module
public class ComonModule {
    @Provides
    public Test4 provideTest4() {
        return new Test4();
    }

}
  • 再看父組件ApplicationComponent 属桦,定義個(gè)抽象方法getCommonComponent()熊痴,把該子組件提供出去。需要用到該子組件的組件都要提供這么一個(gè)抽象方法聂宾,把子組件提供出去果善。
@PerActivity
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
    void inject(DemoApplication application);
    LocationManager getLocationManager();
    CommonComponent getCommonComponent();
}
  • 父組件的Module-- *AndroidModule *
@Module
public class AndroidModule {
    private final DemoApplication application;

    public AndroidModule(DemoApplication application) {
        this.application = application;
    }

    @Provides
    @PerActivity
    public LocationManager provideLoctionManager() {
        return (LocationManager) application.getSystemService(LOCATION_SERVICE);
    }
}
  • 注入到DemoApplication中,先 調(diào)用ApplicationComponent 的getCommonComponent()方法系谐,得到子組件巾陕,然后調(diào)用子組件的 getText4()方法,得到Text4的實(shí)例纪他, 具體看代碼
public class DemoApplication extends Application {
    @Inject
    LocationManager locationManager;
    private ApplicationComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerApplicationComponent.builder()
                .androidModule(new AndroidModule(this))
                .build();
    /* //Component0中用單例注解鄙煤,Module中也用單例注解,并且只獲取一個(gè)子Component茶袒,則可以保持單例
       CommonComponent commonComponent = component().getCommonComponent();
        Test4 test4 = commonComponent.getText4();
        Test4 test41 = commonComponent.getText4();*/
        //這種寫法梯刚,即使Component中,Module中都用了單例注解薪寓,也無法實(shí)現(xiàn)單例
        Test4 test4 = component.getCommonComponent().getText4();
        Test4 test41 = component.getCommonComponent().getText4();
        component().inject(this);
        Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();

    }

    public ApplicationComponent component() {
        return component;
    }
}

子組件的總結(jié):

  • 子組件不能獨(dú)立使用亡资,必須依靠父組件才能向外提供實(shí)例。
  • 父組件必須提供抽象方法向叉,將該子組件提供出去锥腻。然后才能拿到子組件,并獲取子組件提供的類的實(shí)例母谎。

三:?jiǎn)卫氖褂聾Scope注解瘦黑;

  1. 如何實(shí)現(xiàn)單例,依然是看代碼
  • AppModule的代碼:
import com.zhang.testing.simplemvpdemo.bean.Principal;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * Created by zyg on 2016/11/15.
 */
@Module

public class AppModule {
    @Provides
    @Singleton
    public Principal providePrinciple() {
        return new Principal();
    }
}
  • AppComponent的代碼
package com.zhang.testing.simplemvpdemo.di.component;

import com.zhang.testing.simplemvpdemo.MyApplication;
import com.zhang.testing.simplemvpdemo.di.module.AppModule;

import javax.inject.Singleton;

import dagger.Component;

/**
 * Created by zyg on 2016/11/15.
 */
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication application);
}

注入代碼就不貼了,看效果棉钧,實(shí)現(xiàn)了單例西疤。那么如何實(shí)現(xiàn)單例禾进?层释?

  • 就是Module 中和 Component中都用@Singleton,注解(注意Module中應(yīng)該注解在提供方法哪里),即必須成對(duì)出現(xiàn)才能實(shí)現(xiàn)單例
  • 如果Module 中沒有注解楣嘁,Component中可注解磅轻,可不注解,但是Module中提供了注解逐虚,Component中必須提供注解聋溜,否則編譯無法通過,必須成對(duì)出現(xiàn)才能實(shí)現(xiàn)單例哦叭爱!重要事情說兩遍了4樵辍!买雾!
  • 如果某個(gè)類是用@Inject注解把曼,為Component提供實(shí)例的杨帽,那么無法在該類內(nèi)使用注解實(shí)現(xiàn)單例,只能在Module中的Provide方法里使用注解實(shí)現(xiàn)單例
image

2. 那么你要問了@Singleton祝迂,是神馬睦尽??型雳,其實(shí)@Singleton当凡,只是Dagger2為給我們提供的默認(rèn)單例注解,其實(shí)它靠的還是@Scope纠俭, 越來越糊涂了沿量??有木有冤荆?不著急馬上就會(huì)豁然開朗朴则!看下@Singleton的代碼

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

看到了嗎?@Singleton里面有個(gè)@Scope的注解〉黾颍現(xiàn)在還不是解釋的時(shí)候乌妒。那我們也寫個(gè)像@Singleton的注解,看看能不能用外邓。我們自定義了個(gè)@OnlyInstance 撤蚊,然后我們把上面代碼的 AppComponent和AppModule中的@Singleton,全部替換為@OnlyInstance 损话,運(yùn)行后發(fā)現(xiàn)和用@Singleton的效果一摸一樣侦啸,同樣實(shí)現(xiàn)了單例。那么說明了什么呢丧枪?

@Retention(RUNTIME)
@Scope
public @interface OnlyInstance {
}
  1. 我們自定義的注解@OnlyInstance 和Dagger2提供的注解@Singleton光涂,效果相同。他們都能實(shí)現(xiàn)單例拧烦,因?yàn)橹虚g都有@Scope這個(gè)注解忘闻。
  2. @Scope 是個(gè)能提供局部單例的注解,這個(gè)注釋的意思就是作用域屎篱,在作用域內(nèi)保持單例服赎,同屬于一個(gè)作用域,共用一個(gè)相同實(shí)例交播。這會(huì)與component的生命周期(不是整個(gè)應(yīng)用)關(guān)聯(lián).只是Component的生命周期內(nèi)哦重虑!有了它我們就能自定義很多個(gè)可以提供單例的注解。為什么需要自定義很多個(gè)注解秦士?缺厉?
  • 因?yàn)楦鱾€(gè)組件Component要獨(dú)立出來,而要獨(dú)立出來就不能在同一個(gè)作用域,那么就不能使用同一個(gè)注解.當(dāng)然如果兩個(gè)不相關(guān)的Component之間提针,可以用相同的注解命爬。
    • 但是如果兩個(gè)Component是依賴關(guān)系則不能用相同的單例注解。
    • 那么問題來了辐脖,我們說@Scope,能讓實(shí)例在Component生命周期內(nèi)保持單例饲宛,那如果我想全局保持單例,與整個(gè)應(yīng)用的生命周期一樣嗜价,那么該怎么做呢艇抠?其實(shí)我們?cè)谏厦嬲f依賴的時(shí)候已經(jīng)貼過代碼,只是沒有詳細(xì)的去解釋而已久锥。
      • Test3注入MainActivity中需要傳入?yún)?shù)LocationManager的實(shí)例家淤,但是MainActivityComponent對(duì)應(yīng)Module中并沒有提供這個(gè)實(shí)例,那么只能依賴ApplicationComponent瑟由。先看Test3的代碼
public class Test3 {
    private LocationManager locationManager;
    public Test3(LocationManager manager) {
        this.locationManager = manager;
    }
    public String sayName(){
        return "我是Test3";
    }
}

父組件的代碼絮重,注意這里用的單例注解是 @PerActivity

@PerActivity//當(dāng)Module中使用了單例注解,Component中必須使用單例注解歹苦。
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
    void inject(DemoApplication application);
    LocationManager getLocationManager();//將LocationManager 提供給子控件
}

父組件對(duì)應(yīng)的Module,注意這里用的單例注解是 @PerActivity

@Module
public class AndroidModule {
    private final DemoApplication application;
    public AndroidModule(DemoApplication application) {
        this.application = application;
    }
    @Provides
    @PerActivity// 這是自定義單例注解
    public LocationManager provideLoctionManager() {
        return (LocationManager) application.getSystemService(LOCATION_SERVICE);
    }  
}

在看子組件的代碼注意這里的單例注解我們用的是@OnlyInstance青伤,和父組件的不一樣,如果一樣會(huì)報(bào)錯(cuò)殴瘦。

@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = CModule.class)
public interface MainActivityComponent {
    void inject(MainActivity activity);
}

在看看與子控件相關(guān)的Module代碼潮模,這里Module我們并沒有讓Test3也是單例狀態(tài),所以Test3的注入不是單例的痴施。但是我們的目的是看LocationManager 注入是不是單例的。

@Module
public class CModule {
    @Provides
    Test3 provdeText3(LocationManager locationManager){
      return   new Test3(locationManager);
    }
    /**
     * 依賴中單例的總結(jié):
     * 單例有源頭性究流,如果上游是單例接收必須單例辣吃。
     * 父類Component提供的是單例,子Component必須單例芬探,
     * 但僅限于Component,子的Module不受影響
     * Component 和Module之間神得,Module 是單例,Component必須單例偷仿。
     * @Scope的一個(gè)注釋哩簿,這個(gè)注釋的意思就是作用域,
     * 在作用域內(nèi)保持單例:同屬于一個(gè)作用域酝静,共用一個(gè)相同實(shí)例
     * 為什么要新增一個(gè)呢节榜,因?yàn)楦鱾€(gè)組件需要獨(dú)立出來,
     * 因此如果是依賴關(guān)系别智,則需要各自在不同的注釋作用域里面
     * (所以自定義一個(gè)@OnlyInstance)
     * 子Component 和 父Component 作用域不能相同宗苍,必須各自在不同的作用域里
     * 但是 Component和 Module之間必須用相同的作用域,當(dāng)然如果Module沒有,Component就隨意了
     * 然后我們又定義了一個(gè)@PerActivity
     * 我們將之前的@Singleton用新建的(自定義的@PerActivity)替換掉讳窟,
     * 驗(yàn)證兩次的生成代碼让歼,發(fā)現(xiàn)一模一樣,
     * @Singleton丽啡,只是Dagger2為我們提供的一個(gè)單例注解谋右。我們可以根據(jù)自己的需求自定義自己的單例注解
     * 但是我們定義的時(shí)候要命名最好是有意義的,@PerActivity补箍,我們希望它的作用是保持Activity內(nèi)單例改执,見名知意吧!
     *
     * */
}

接下來我們?cè)倏聪伦⑷氪a馏予。這里applicationComponent,方法需要的參數(shù)applicationComponent的實(shí)例天梧,我們是從DemoApplication中獲取的。只有保證了applicationComponent的唯一性才能保證單例超出Component生命周期后依然有效霞丧。這也變相說明@Scope注解實(shí)現(xiàn)了Component內(nèi)單例呢岗,與Component生命周期相關(guān),而不是與整個(gè)應(yīng)用生命周期相關(guān)蛹尝。

public class MainActivity extends AppCompatActivity {
    @Inject
    Test3 test3;
    @Inject
    Test3 test2;
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main)
        DaggerMainActivityComponent.builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build()//applicationComponent方法需要的參數(shù)是從DemoApplication獲取的后豫,沒有重新新建
                .inject(this);
        Toast.makeText(this, test2.sayName(), Toast.LENGTH_SHORT).show();
    }
}

然后我們看下效果圖


image
  • 子組件提供的類的實(shí)例無法通過注解的方式直接實(shí)現(xiàn)單例,但是我們可以通過只獲取一個(gè)子組件Component而實(shí)現(xiàn)單例突那。而且子組件和父組件可以使用相同的單例注解挫酿。具體看代碼吧!
    • 子組件的代碼
@PerActivity
@Subcomponent(modules = ComonModule.class)
public interface CommonComponent {
    Test4 getText4();
} 

子組件相對(duì)應(yīng)的Module

@Module
public class ComonModule {
    @PerActivity
    @Provides
    public Test4 provideTest4() {
        return new Test4();
    }

}

調(diào)用時(shí)候只獲取一個(gè)子Component愕难,就能實(shí)現(xiàn)單例早龟,代碼如下

public class DemoApplication extends Application {
private ApplicationComponent component;
@Override
public void onCreate() {
    super.onCreate();
    component = DaggerApplicationComponent.builder()
            .androidModule(new AndroidModule(this))
            .build();
    CommonComponent commonComponent = component().getCommonComponent();
    Test4 test4 = commonComponent.getText4();
    Test4 test41 = commonComponent.getText4();
    component().inject(this);
    Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();
}
public ApplicationComponent component() {
    return component;
}
}
dagger2-4

單例的總結(jié):我們自定義單例注解的時(shí)候,最好每個(gè)自定義的名稱都有意義猫缭,比如在Activity內(nèi)保持單例葱弟,那么就定義為@perAcvitity.

四: @Scope是用來自定義單例注解的,那么還有沒有其他的猜丹,可以自定義的呢芝加?就喜歡你這好奇的性格,還真有射窒,它就是@Qualifier藏杖。它是做什么的呢?看個(gè)栗子!

  • 假設(shè)有這么個(gè)類需要注入Test5,當(dāng)傳入的值不同時(shí)脉顿,它的屬性就不同蝌麸。但是他們都是Test5類,系統(tǒng)如何區(qū)分他們呢弊予?他們沒辦法區(qū)分祥楣。于是我們就得告訴他們,哪個(gè)是哪個(gè)。误褪。责鳍。。兽间,我們這里先用Dagger2提供的一個(gè)注解@Named历葛。它需要傳入一個(gè)字符串,來區(qū)別不同的實(shí)例嘀略。
public class Test5 {
    private int mFlag;
    public Test5(int flag) {
        this.mFlag = flag;
    }
    public String signature() {
        if (mFlag == 1) {
            return "我是美女恤溶。。帜羊。";
        } else if(mFlag==0){
            return "我是帥哥";
        }else if(mFlag==2){
            return "我是男人";
        }else {
            return "我是女人";
        }
    }
}
  • 接著來看Module 里面怎么寫的咒程。
@Module
public class AndroidModule {
    private final DemoApplication application;

    public AndroidModule(DemoApplication application) {
        this.application = application;
    }

    @Provides
    @PerActivity
    public LocationManager provideLoctionManager() {
        return (LocationManager) application.getSystemService(LOCATION_SERVICE);
    }

    @PerActivity
    @Provides
    public Context provideContext() {
        return application.getApplicationContext();
    }
    @PerActivity
    @Provides
    @Named("boy")
    public Test5 provideBoy() {
        return new Test5(0);
    }
    @PerActivity
    @Provides
    @Named("girl")
    public Test5 provideGirle() {
        return new Test5(1);
    }
}
  • 在看看怎么注入的,注入的時(shí)候也要注解清楚讼育,不然系統(tǒng)還是無法區(qū)分他們的帐姻。這樣就完成注入了。
public class DemoApplication extends Application {
  
    @Inject
    @Named("boy")
    Test5 boy;
    @Inject
    @Named("girl")
    Test5 girl;
    private ApplicationComponent component;
    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerApplicationComponent.builder()
                .androidModule(new AndroidModule(this))
                .build();
    /* //Component0中用單例注解奶段,Module中也用單例注解饥瓷,并且只獲取一個(gè)子Component,則可以保持單例
       CommonComponent commonComponent = component().getCommonComponent();
        Test4 test4 = commonComponent.getText4();
        Test4 test41 = commonComponent.getText4();*/
        //這種寫法痹籍,即使Component中呢铆,Module中都用了單例注解,也無法實(shí)現(xiàn)單例
        Test4 test4 = component.getCommonComponent().getText4();
        Test4 test41 = component.getCommonComponent().getText4();
        component().inject(this);
        Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();

    }

    public ApplicationComponent component() {
        return component;
    }
}
dagger2_9
  • 等等蹲缠,我們不是說自定義注解的嗎棺克?是的,@Name(xx)线定,是Dagger2提供的注解逆航。我們看看它的代碼。
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}
  • 我們自定義個(gè)幾個(gè)試一試
    男孩
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForBoy {
}

女孩

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForGirl {
}
  • 然后我們用下試一試渔肩,直接上代碼了哦!首先Module類拇惋,這里為了和原來的@Name區(qū)分開來周偎,我把他們叫做男的和女的
@Module
public class AndroidModule {
    private final DemoApplication application;

    public AndroidModule(DemoApplication application) {
        this.application = application;
    }

    @Provides
    @PerActivity
    public LocationManager provideLoctionManager() {
        return (LocationManager) application.getSystemService(LOCATION_SERVICE);
    }

    @PerActivity
    @Provides
    public Context provideContext() {
        return application.getApplicationContext();
    }

    @PerActivity
    @Provides
    @Named("boy")//Dagger2提供的默認(rèn)注解
    public Test5 provideBoy() {
        return new Test5(0);
    }

    @PerActivity
    @Provides
    @Named("girl")
    public Test5 provideGirle() {
        return new Test5(1);
    }
    @PerActivity
    @Provides
    @ForBoy//因傳入的值不相同,所以屬性不相同撑帖,而Dagger2無法區(qū)分蓉坎,我們用注解告訴系統(tǒng),他們是不同的胡嘿,有區(qū)別的蛉艾,
    public Test5 provideMan(){//因?yàn)镈agger2是以返回的類的名稱來區(qū)分不同的返回方法的。
        return new Test5(2);
    }
    @PerActivity
    @Provides
    @ForGirl//我們自定義的注解
    public Test5 provideWoman(){
        return new Test5(3);
    }
}

再看注入的地方。

public class DemoApplication extends Application {
    @Inject
    LocationManager locationManager;
    @Inject
    @Named("boy")//注入到的地方也要有相應(yīng)的注解勿侯,否則Dagger2還是無法區(qū)分的
    Test5 boy;
    @Inject
    @Named("girl")
    Test5 girl;
    @Inject
    @ForBoy//自定義的注解
    Test5 man;
    @Inject
    @ForGirl
    Test5 woman;

    private ApplicationComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerApplicationComponent.builder()
                .androidModule(new AndroidModule(this))
                .build();
    /* //Component0中用單例注解拓瞪,Module中也用單例注解,并且只獲取一個(gè)子Component助琐,則可以保持單例
       CommonComponent commonComponent = component().getCommonComponent();
        Test4 test4 = commonComponent.getText4();
        Test4 test41 = commonComponent.getText4();*/
        //這種寫法祭埂,即使Component中,Module中都用了單例注解兵钮,也無法實(shí)現(xiàn)單例
        Test4 test4 = component.getCommonComponent().getText4();
        Test4 test41 = component.getCommonComponent().getText4();
        component().inject(this);
        Toast.makeText(this, locationManager.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();

    }

    public ApplicationComponent component() {
        return component;
    }
}
image
  • 另外蛆橡,如果我們把boy,girl提供給依賴它的組件掘譬,那么提供方法里也要用相應(yīng)的注解泰演,否則報(bào)錯(cuò)的。具體看代碼葱轩,一看就懂了睦焕。
@PerActivity
@Component(modules = AndroidModule.class)
public interface ApplicationComponent {
    void inject(DemoApplication application);
    LocationManager getLocationManager();

    CommonComponent getCommonComponent();
//提供給子組件使用的時(shí)候也要有相應(yīng)的注解。不然怎么分辨呢
    @Named("boy")
    Test5 provideBoy();

    @Named("girl")
    Test5 provideGirl();

    @ForBoy
    Test5 provideMan();

    @ForGirl
    Test5 provideWoman();

}

就是這么自定義的酿箭,至于為什么要自定義复亏,每次敲入不同的字符串你不煩嗎?萬一敲錯(cuò)了呢缭嫡?那又怎么辦5抻!

五:懶加載妇蛀,這個(gè)比較簡(jiǎn)單耕突。

  • Component和Module中的寫法沒任何變化,只是在注入的地方略有不同评架。用 Lazy<>
    把懶加載的類包裹起來眷茁,用的時(shí)候調(diào)用get方法獲取類的實(shí)例
public class MainActivity extends AppCompatActivity {
    @ForGirl
    Lazy<Test5> beautifulGirl;//漂亮的女孩都比較懶
//注入的地方懶加載這么寫。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main)
        DaggerMainActivityComponent.builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build()
                .inject(this);
        Toast.makeText(this, beautifulGirl.get().signature(), Toast.LENGTH_SHORT).show();
        //注入完成后只是提供一個(gè)可以生成Test5的對(duì)象纵诞,通過get(),才能獲得我們需要的真正實(shí)例
    }
}

六: 多綁定到Set中上祈,一個(gè)Component可以有多個(gè)Module,同時(shí)不同Module中的相同數(shù)據(jù)類型的元素可以綁定到同一個(gè)Set中浙芙。這里我們列舉了兩種類型的Set登刺,Set<String>和Set<Integer>

第一個(gè)ModuleA,第一個(gè)方法提供Set<String> 元素為:"ABC" ,第二個(gè)方法提供了Set<String>元素為:"abc"
第三個(gè)方法提供了Set<String>元素為:"DEF", "GHI" 嗡呼,第四個(gè)方法提供了Set<Integer> 元素為:1

@Module
public class ModuleA {

    @Provides
    @IntoSet
    public String provideString(LocationManager locationManager) {
        return "ABC";
        //注入到Set<String>中纸俭,單個(gè)元素就用 @IntoSet
    }

    @Provides
    @IntoSet
    public String provideSecond(LocationManager locationManager) {
        return "abc";
        //注入到Set<String>中單個(gè)元素就用 @IntoSet
    }.

    @Provides
    @ElementsIntoSet
    public Set<String> provideStings(LocationManager manager) {
        return new HashSet<String>(Arrays.asList("DEF", "GHI"));
        //注入到Set<String>中,列表和多個(gè)元素用@ElementsIntoSet
    }
    @Provides
    @IntoSet
    public Integer provideInterger(LocationManager locationManager) {
        return 1;
        //注入到Set<Integer>中
    }
    /**
     * 這里需要注意的就是南窗,在組件里面加入多個(gè)綁定的時(shí)候揍很,
     * module的里面必須要有一個(gè)是@IntoSet 這個(gè)作為第一個(gè)標(biāo)記郎楼,
     * 否則會(huì)出錯(cuò),可以多個(gè)@IntoSet標(biāo)記窒悔。
     如果是列表類型的呜袁,則使用@ElementsIntoSet就ok了。
     * */
}

ModuleB,這個(gè)Module提供了Set<String>的元素為:"def", "ghi" 和 Set<Integer> 元素為:3, 2

@Module
public class ModuleB {
    @Provides
    @ElementsIntoSet
    public Set<String> provideStings(LocationManager manager){
        return new HashSet<String>(Arrays.asList("def", "ghi"));
        //注入到Set<String>蛉迹,多個(gè)元素用@ElementsIntoSet
    }
    @Provides
    @ElementsIntoSet
    public Set<Integer> provideIntegers(LocationManager manager) {
        return new HashSet<Integer>(Arrays.asList(3, 2));
        //注入到Set<Integer>中,因?yàn)槭橇斜硇退?@ElementsIntoSet注解
    }
}

MainActivityComponent ,依賴了ApplicationComponent傅寡,注意:這里有個(gè)抽象方法 Set<String> getStrings();把Set<String> 提供出去的。具體什么用北救,我們待會(huì)說荐操。

@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = {ModuleA.class, ModuleB.class})
public interface MainActivityComponent {
    void inject(MainActivity activity);
    Set<String> getStrings();
}

現(xiàn)在就該到注入環(huán)節(jié)了。注入方式有兩種哦

  1. 第一種注入方式珍策,我們定義了相應(yīng)類型的Set,接收注入托启。
public class MainActivity extends AppCompatActivity {
    @Inject
    Set<String> mStringSet;//注入的為Set<String>
    @Inject
    Set<Integer> integerSet;//注入的為 Set<Integer>
    @Inject
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainActivityComponent.builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build()
                .inject(this);
    }
}
image

如果我們?cè)贑omponent中移除ModuleB那么ModuleB中提供的相應(yīng)元素就不會(huì)注入到相應(yīng)Set中了,另外Dagger2會(huì)把數(shù)據(jù)類型相同的都注入到同一個(gè)Set中攘宙,提供類型為 Set<Integer>注入到integerSet里屯耸,提供類型為Set<String>mStringSet中。

  1. 第二種方式:還記得我們剛在MainActivityComponent 中提醒大家注意的那個(gè)抽象方法嗎蹭劈?第二個(gè)方法首先就是MainActivityComponent 中得定義一個(gè)抽象方法把Set<String>提供出來疗绣。這里我們只做個(gè)演示。所以就只做個(gè)Set<String> 的
public class MainActivity extends AppCompatActivity {
    Set<String> mStringSet;//注入的為Set<String>
    @Inject
    Set<Integer> integerSet;//注入的為 Set<Integer>
    @Inject
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mStringSet = DaggerMainActivityComponent
                .builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build()
                .getStrings();
       
    }
}

看效果圖
image

多綁定到Map中铺韧,既然可以綁定到Set那么Map也不例外

首先看MyModule1 多矮,分別提供了幾種類型的Map 同Set一樣,Map會(huì)把Key類型一致哈打,值類型一致的綁定到同一個(gè)Map中

@Module
public class MyModule1 {
    @Provides
    @IntoMap
    @StringKey("foo")
    static Long provideFooValue(){
        return 100L;
        //綁定到Map<String,Long>中
    }
    @Provides
    @IntoMap
    @StringKey("goo")
    static Long provideGooValue(){
        return 100L;
        //綁定到Map<String,Long>中
    }
    @Provides
    @IntKey(2)
    @IntoMap
    static int provideIntValue(){
        return 200;
        //綁定到Map<Integer Integer>中
    }
    @Provides
    @IntoMap
    @LongKey(1L)
    static Long provideLongValue(){
        return 100L;
        //綁定到Map<Long,Long> 中
    }
    @Provides
    @IntoMap
    @ClassKey(Test3.class)
    static String provideTest3Value(){
        return "Value for Test3";
        //key為Test3.class塔逃,用的是Dagger2的標(biāo)注,所以key為Class<?>,值為String的Map<Class<?>,Sting>
    }
}

在MyModule1 中料仗,我們看到各種類型的@MapKey注解的給中MapKey湾盗。隨便看個(gè) @ClassKey的源碼

@Beta
@Documented
@Target(METHOD)
@MapKey
public @interface ClassKey {
  Class<?> value();
}

在MyModule2 中我們也自定義幾個(gè)@MapKey的注解

@Module
public class MyModule2 {
    @Provides
    @IntoMap
    @MyEnumKey(MyEnum.ABC)
    public String provideABCValue() {
        return "Value for ABC";
        //綁定到 Map<MyModule2.MyEnum, String> 中去
    }

    @Provides
    @IntoMap
    @MyNumberClassKey(BigDecimal.class)
    public String provideNumberClassValue() {
        return "BigDecimal Value";
        //綁定到Map< Class<? extends Number>,String>中
    }

    //自定義枚舉
    public static enum MyEnum {
        ABC, DEF;
    }

    //自定義注解枚舉類型的@MapKey
    @MapKey
    @interface MyEnumKey {
        MyEnum value();
    }

    //自定義注解 @MapKey
    @MapKey
    @interface MyNumberClassKey {
        Class<? extends Number> value();
    }
}

然后我們看MainActivityComponent 的代碼,同樣立轧,這里也有個(gè)抽象方法 Map<String, Long> getMap(); 把 Map<String, Long>的提供出去格粪。也就是說 Map和Set一樣。也有兩種注入方式氛改。這里我們只看一種匀借。另一種和Set一樣。

@OnlyInstance
@Component(dependencies = ApplicationComponent.class,modules = {ModuleA.class, ModuleB.class,MyModule1.class, MyModule2.class,CModule.class})
public interface MainActivityComponent {
    void inject(MainActivity activity);
    Set<String> getStrings();
    Map<String, Long> getMap();
}

看注入的地方代碼

public class MainActivity extends AppCompatActivity {
    @Inject
    Test3 test3;
    @Inject
    Test3 test2;
    @Inject
    Test2 test21;//注入這個(gè)需要提供Set<String>為參數(shù)
    @Inject
    Set<String> mStringSet;//注入的為Set<String>
    @Inject
    Map<Integer, Integer> mIntegerIntegerMap;//Key Integer,值為Integer
    @Inject
    Map<String, Long> mapTest;//Key為String平窘,值為Long的就會(huì)注入到這個(gè)里面
    @Inject
    Map<Long, Long> mapLongkey;//key 為Long,值為Long的就會(huì)注入到這個(gè)里面
    @Inject
    Map<MyModule2.MyEnum, String> myEnumStringMap;
    @Inject
    Map<Class<? extends Number>, String> classStringMap;//自定義Key
    @Inject
    Map<Class<?>, String> test3StringMap;//key為Test3.class凳怨,用的是Dagger2的標(biāo)注瑰艘,所以key為Class<?>
    @Inject
    Set<Integer> integerSet;//注入的為 Set<Integer>
    @Inject
    @Named("boy")
    Test5 boy;
    @Inject
    @Named("girl")
    Test5 girl;
    @Inject
    @ForBoy
    Test5 man;
    @Inject
    @ForGirl
    Test5 woman;
    @Inject
    @ForGirl
    Lazy<Test5> beautifulGirl;//漂亮的女孩都比較懶


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     /*   MainActivityComponent mainActivityComponent = DaggerMainActivityComponent
                .builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build();
        mStringSet = mainActivityComponent
                .getStrings();*/

        DaggerMainActivityComponent.builder()
                .applicationComponent(((DemoApplication) getApplication()).component())
                .build()
                .inject(this);
        Toast.makeText(this, test2.sayName(), Toast.LENGTH_SHORT).show();
        Toast.makeText(this, beautifulGirl.get().signature(), Toast.LENGTH_SHORT).show();
        //注入完成后只是提供一個(gè)可以生成Test5的對(duì)象是鬼,通過get(),才能獲得我們需要的真正實(shí)例
    }
}
image

Map和Set的原理是一樣的,只是Map的key可以通過自定義的方式來定義紫新。對(duì)著擼一把均蜜。那么Demo地址:DaggerTest

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芒率,隨后出現(xiàn)的幾起案子囤耳,更是在濱河造成了極大的恐慌,老刑警劉巖偶芍,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件充择,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡匪蟀,警方通過查閱死者的電腦和手機(jī)椎麦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來材彪,“玉大人观挎,你說我怎么就攤上這事《位” “怎么了嘁捷?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長显熏。 經(jīng)常有香客問我雄嚣,道長,這世上最難降的妖魔是什么佃延? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任现诀,我火速辦了婚禮,結(jié)果婚禮上履肃,老公的妹妹穿的比我還像新娘仔沿。我一直安慰自己,他們只是感情好尺棋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布封锉。 她就那樣靜靜地躺著,像睡著了一般膘螟。 火紅的嫁衣襯著肌膚如雪成福。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天荆残,我揣著相機(jī)與錄音奴艾,去河邊找鬼。 笑死内斯,一個(gè)胖子當(dāng)著我的面吹牛蕴潦,可吹牛的內(nèi)容都是我干的像啼。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼潭苞,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忽冻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起此疹,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤僧诚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蝗碎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湖笨,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年衍菱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赶么。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脊串,死狀恐怖辫呻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情琼锋,我是刑警寧澤放闺,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站缕坎,受9級(jí)特大地震影響怖侦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谜叹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一匾寝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荷腊,春花似錦艳悔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疾忍,卻和暖如春乔外,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背一罩。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工杨幼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毅待。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓随珠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碳褒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歹撒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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