Dagger2 入門晉級(jí)篇,直奔主題吧复濒!
一 :組件之間的依賴
- 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,子組件(公共組件)
- 如果有一個(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注解瘦黑;
- 如何實(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)單例
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 {
}
- 我們自定義的注解@OnlyInstance 和Dagger2提供的注解@Singleton光涂,效果相同。他們都能實(shí)現(xiàn)單例拧烦,因?yàn)橹虚g都有@Scope這個(gè)注解忘闻。
- @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();
}
}
然后我們看下效果圖
- 子組件提供的類的實(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;
}
}
單例的總結(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;
}
}
- 等等蹲缠,我們不是說自定義注解的嗎棺克?是的,@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;
}
}
- 另外蛆橡,如果我們把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é)了。注入方式有兩種哦
- 第一種注入方式珍策,我們定義了相應(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);
}
}
如果我們?cè)贑omponent中移除ModuleB那么ModuleB中提供的相應(yīng)元素就不會(huì)注入到相應(yīng)Set中了,另外Dagger2會(huì)把數(shù)據(jù)類型相同的都注入到同一個(gè)Set中攘宙,提供類型為 Set<Integer>注入到integerSet里屯耸,提供類型為Set<String>mStringSet中。
- 第二種方式:還記得我們剛在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();
}
}
看效果圖多綁定到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í)例
}
}