前言
Dagger2
是目前Android
流行的框架搭配之一俐芯。所以棵介,學(xué)起來(lái)!(P.s:看了好多好多的文章解讀~)
原理解讀
Dagger2是什么泼各?
官方介紹:
A fast dependency injector for Java and Android.
譯:Java和Android的快速依賴關(guān)系注入器鞍时。
個(gè)人理解:
Dagger
就是用來(lái)創(chuàng)造出一個(gè)容器,所有需要被依賴的對(duì)象在Dagger
的容器中實(shí)例化扣蜻,并通過(guò)?
Dagger
注入到合適的地方,實(shí)現(xiàn)解耦及塘。
什么是依賴注入莽使?
依賴注入,英文名
Dependency Injection
笙僚,簡(jiǎn)稱(chēng)DI芳肌。簡(jiǎn)單說(shuō)就是目標(biāo)類(lèi)(目標(biāo)類(lèi)需要進(jìn)行依賴初始化的類(lèi))中所依賴的其他的類(lèi)的初始化過(guò)程,不是通過(guò)手動(dòng)編碼的方式創(chuàng)建,而是通過(guò)技術(shù)手段可以把其他的類(lèi)的已經(jīng)初始化好的實(shí)例自動(dòng)注入到目標(biāo)類(lèi)中亿笤。(P.s:不明白沒(méi)關(guān)系翎迁,看文章你就明白了!認(rèn)真臉>谎Α)
優(yōu)點(diǎn)
- 增加開(kāi)發(fā)效率汪榔,神曲重復(fù)的簡(jiǎn)單體力勞動(dòng)
- 更好的管理類(lèi)實(shí)例
- 解耦
- 便于擴(kuò)展和維護(hù)
缺點(diǎn)
- 相對(duì)于其他框架,有一定學(xué)習(xí)成本肃拜,需要時(shí)間消化痴腌。我自己就看了好多好多文章。燃领。士聪。。
少?gòu)U話猛蔽!入正題剥悟!
Dagger2
提供的注解:@Inject
、@Component
和@Module
曼库、@Provieds
在描述第一組注解的作用前区岗,我們來(lái)看一則例子:
? 假設(shè)領(lǐng)導(dǎo)下午要出去視察民情,需要一輛公交車(chē)凉泄,司機(jī)就不用請(qǐng)了躏尉,領(lǐng)導(dǎo)做表率自己開(kāi),小秘把領(lǐng)導(dǎo)的指示告訴了車(chē)場(chǎng)調(diào)度員后众。
??找輛公交車(chē)要停放在停車(chē)場(chǎng)(Bus要注入到ParkingActivity
)胀糜,停車(chē)場(chǎng)不管公交車(chē)按什么路線停車(chē)(ParkingActivity不管Bus是如何注入的
),車(chē)場(chǎng)調(diào)度員會(huì)負(fù)責(zé)好管理(Dagger2容器會(huì)將Bus的注入到ParkingActivity
)蒂誉。public class Bus { @Inject public Bus() { } } public class ParkingActivity extends Activity { @Inject Bus mBus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); DaggerParkingComponent.create().inject(this);//DaggerParkingComponent類(lèi)需要編譯才會(huì)生成 ((TextView) findViewById(R.id.text)).setText(mBus.toString()); } } @Component public interface ParkingComponent { void inject(ParkingActivity activity); }
DaggerParkingComponent
類(lèi)是編譯過(guò)后Dagger2
自動(dòng)生成的教藻,是ParkingComponent
的實(shí)現(xiàn)類(lèi),可以說(shuō)DaggerParkingComponent
就是實(shí)際的車(chē)場(chǎng)調(diào)度員右锨,ParkingComponent
是對(duì)車(chē)場(chǎng)調(diào)度員的約束括堤,在onCreate
方法完成了注入過(guò)程。
@Inject
的作用(1)注解在屬性中表示該屬性需要依賴注入绍移,不能使用
private
修飾悄窃,示例代碼表示需要注入屬性?
mBus
(Bus的車(chē)位):@Inject Bus mBus;
(2)注解在方法中表示該方法需要依賴注入,不能是抽象方法蹂窖,不能使用
private
修飾轧抗,示例代碼表示? 需要注入方法
injectBus
://@Inject Bus mBus; @Inject public void injectBus(Bus bus) { mBus = bus; }
? 方法注入的參數(shù)同樣由
Dagger2
容器提供,以上代碼的目的與第一點(diǎn)介紹的屬性注入一樣瞬测,都是為了注入
mBus
横媚,如果目的是注入屬性的話纠炮,方法注入和屬性注入基本沒(méi)有區(qū)別,屬性注入是Dagger2
中使用最多的一個(gè)注入方式灯蝴。
??那么什么情況下應(yīng)該使用方法注入恢口?比如依賴需要this對(duì)象的時(shí)候,方法注入可以提供安全的this對(duì)象穷躁。
??注意耕肩,Dagger2
容器先調(diào)用屬性注入,然后再方法注入折砸,若把示例代碼mBus
的@Inject
取消注釋?zhuān)藭r(shí)mBus
會(huì)注入2次看疗,并且兩次注入的Bus也不相同。(3)注解在構(gòu)造方法中表示此類(lèi)能為
Dagger2
提供依賴關(guān)系睦授,Dagger2
可以使用這個(gè)構(gòu)造方法構(gòu)建對(duì)象(Bus的來(lái)歷):@Inject public Bus() { }
? 如果有多個(gè)構(gòu)造函數(shù)两芳,只能注解一個(gè),否則編譯報(bào)錯(cuò)去枷。
@Component
的作用一般用來(lái)注解接口怖辆,被注解的接口在編譯時(shí)會(huì)生成相應(yīng)的實(shí)例。實(shí)例名稱(chēng)一般以
Dagger
為前綴删顶,作為所需注入依賴(ParkingActivity的mBus屬性
)和提供依賴(Bus類(lèi)構(gòu)造方法
)之間的橋梁竖螃,把提供的依賴)注入到所需注入的依賴中(ParkingActivity的mBus屬性
)。例子一總結(jié):通俗說(shuō)逗余,就是
Dagger2
的容器特咆,在例子中是車(chē)場(chǎng)調(diào)度員,把公交車(chē)和停車(chē)場(chǎng)聯(lián)系在一起录粱。車(chē)場(chǎng)調(diào)度員知道停車(chē)場(chǎng)要準(zhǔn)備一輛公交車(chē)腻格,停車(chē)場(chǎng)不需要知道車(chē)是哪里來(lái)的,也不需要知道怎么停啥繁,車(chē)場(chǎng)調(diào)度員找好車(chē)后菜职,停在車(chē)位上就完事嗦哆,等候領(lǐng)導(dǎo)用車(chē)就可以了低矮。兩個(gè)
@Inject
注解形成了依賴關(guān)系,@Component
作為連接這個(gè)關(guān)系的橋梁存在碉纳,尋找到依賴并且注入适室,并且注入與被注入之間互不干涉嫡意,經(jīng)過(guò)編譯@Component
生成Dagger
為前綴的實(shí)例,調(diào)用實(shí)例的方法捣辆。第二組注解例子:
領(lǐng)導(dǎo)想著不妥鹅很,自己沒(méi)開(kāi)過(guò)公交車(chē),為保險(xiǎn)起見(jiàn)還是趕緊吩咐小秘罪帖,去給配個(gè)公交車(chē)司機(jī)促煮,小秘自然跟車(chē)場(chǎng)調(diào)度員說(shuō)了。
??車(chē)場(chǎng)調(diào)度員一想整袁,只是比之前多了一個(gè)步驟菠齿,給公交車(chē)配置一個(gè)司機(jī)(Bus類(lèi)添加String類(lèi)型Driver構(gòu)造方法)。于是打電話給開(kāi)公交車(chē)的隔壁老王坐昙,老王自然是應(yīng)諾了下來(lái)绳匀,于是乎,對(duì)例子一的代碼做一下修改炸客。public class Bus { private String driver; @Inject public Bus(String driver) { this.driver = driver; } } public class ParkingActivity extends Activity { @Inject Bus mBus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dagger); DaggerParkingComponent.create().inject(this);//DaggerParkingComponent類(lèi)需要編譯才會(huì)生成 ((TextView) findViewById(R.id.text)).setText(mBus.toString());//重寫(xiě)B(tài)us的toString()方法能看到打印出"隔壁老王"疾棵,注入成功 } } @Component(modules = ParkingModule.class) public interface ParkingComponent { void inject(ParkingActivity activity); } @Module public class ParkingModule { public ParkingModule() { } @Provides public String provideDriver() { return "隔壁老王"; } }
@Module
的作用該注解與
@Provide
s結(jié)合為Dagger2
提供依賴關(guān)系,對(duì)上文@Inject
第三點(diǎn)的補(bǔ)充痹仙,用于不能用@Inject
提供依賴的地方是尔,如第三方庫(kù)提供的類(lèi),基本數(shù)據(jù)類(lèi)型等不能修改源碼的情況开仰。
@Provieds
的作用
@Provides
僅能注解方法拟枚,且方法所在類(lèi)要有@Module
注解。注解后的方法表示Dagger2
能用該方法實(shí)例對(duì)象提供依賴众弓。按照慣例恩溅,@Provides
方法的命名以provide
為前綴,方便閱讀管理谓娃。例子二總結(jié):首先
@Component
注解包含了一個(gè)ParkingModule
類(lèi)脚乡,表示Dagger2
可以從ParkingModule
類(lèi)查找依賴,Dagger2
會(huì)自動(dòng)查找ParkingModule
類(lèi)有@Provides
注釋的方法實(shí)例依賴滨达,最后完成注入奶稠。
注意1,如果在ParkingModule
里面同樣提供Bus的依賴弦悉,Dagger2
會(huì)優(yōu)先在@Module
注解的類(lèi)上查找依賴窒典,沒(méi)有的情況才會(huì)去查詢類(lèi)的@Inject
構(gòu)造方法,如下面的代碼稽莉,則Bus的司機(jī)就是小王而不是老王了瀑志。@Module public class ParkingModule { public ParkingModule() { } @Provides public String provideDriver() { return "隔壁老王"; } @Provides public Bus provideBus() { return new Bus("樓上小王"); } }
注意2,
@Module
類(lèi)可以從構(gòu)造方法傳入依賴污秆,@Provides
方法也可以有依賴關(guān)系劈猪。
@Provides
方法也有依賴關(guān)系的情況,Dagger2
會(huì)繼續(xù)查找可以提供依賴的方法良拼,類(lèi)似于一種遞歸的狀態(tài)战得,一步一步返回實(shí)例。如下代碼庸推,ParkingModule
構(gòu)造方法傳入driver
為provideDriver
方法提供依賴返回常侦,provideDriver
返回driver
作為provideBus
方法的依賴實(shí)例Bus
浇冰。
ParkingModule
加入有參構(gòu)造方法后,調(diào)用方式也需要變成聋亡,現(xiàn)在司機(jī)就變成了樓下老李了肘习。@Module public class ParkingModule { private String driver; public ParkingModule(String driver) { this.driver = driver; } @Provides public String provideDriver() { return driver; } @Provides public Bus provideBus(String driver) { return new Bus(driver); } } //調(diào)用方式改變 DaggerParkingComponent.builder().parkingModule(new ParkingModule("樓下老李")).build().inject(this);
總結(jié)
最后,來(lái)總結(jié)下依賴注入的大致流程:
1:查找
Module
中是否有該實(shí)例的@Provides
方法坡倔。
1.1:有漂佩,走第2點(diǎn)。
1.2:沒(méi)有罪塔,查找該實(shí)例是否有@Inject構(gòu)造方法投蝉。
??????1.2.1:有,走第3點(diǎn)征堪。
??????1.2.2:沒(méi)有瘩缆,注入失敗。
2:
@Provides
方法是否有參數(shù)
- 2.1:有请契,則回到第1點(diǎn)查找每個(gè)參數(shù)的依賴
- 2.2:沒(méi)有咳榜,實(shí)例該類(lèi)返回一次依賴
3:
@Inject
構(gòu)造方法是否有參數(shù)
- 3.1:有,則回到第1點(diǎn)查找每個(gè)參數(shù)的依賴
- 3.2:沒(méi)有爽锥,實(shí)例該類(lèi)返回一次依賴
4:以上流程遞歸返回注入目標(biāo)的所有依賴涌韩,最后依賴注入。
參考鏈接
dagger2讓你愛(ài)不釋手-基礎(chǔ)依賴注入框架篇
google四件套之Dagger2氯夷。從入門(mén)到愛(ài)不釋手系列