什么是Dagger2
1.Dagger2是一個依賴注入框架满着。如果Class A 內(nèi)部 有一個Class B伟恶,我們稱作Class A依賴Class B
例如:
public class A{
B? b
public A(){
b=new B();
}
}
上述方法代碼耦合度很高羹与,如果B是一個父類鸳劳,我們需要在A中用到不同的B類癞季,是需要不斷創(chuàng)建對象B b1= new B1(),B b2=new B2();
2.依賴注入:是外界根據(jù)需要注入不同的對象锡移。這樣可以有效的降低耦合度。
像這種非自己主動初始化依賴崔赌,而通過外部來傳入依賴的方式意蛀,我們就稱為依賴注入耸别。
參考資料:https://github.com/android-cn/blog/tree/master/java/dependency-injection
public class A{
B b;
public A(B b){
this.b=b;
}
}
安卓應用在初始化對象的時候經(jīng)常需要處理各種依賴關(guān)系。比如說網(wǎng)絡(luò)訪問中使用Retrofit县钥,Gson秀姐,本地存儲中使用shared preference。無一例外若贮,我們都都需要在使用它們的地方進行實例對象構(gòu)建省有,對象之間可能還存在著各種各樣的依賴關(guān)系。依賴注入(Dependency Injection谴麦,簡稱DI)是用于削減計算機程序的耦合問題的一個法則蠢沿。對象在被創(chuàng)建的時候,由一個調(diào)控系統(tǒng)內(nèi)所有對象的外界實體將其所依賴的對象的引用傳遞給它匾效。也可以說舷蟀,依賴被注入到對象中。Dagger2 正是一個依賴注入框架面哼,使用代碼自動生成創(chuàng)建依賴關(guān)系需要的代碼野宜。減少很多模板化的代碼,更易于測試魔策,降低耦合匈子,創(chuàng)建可復用可互換的模塊。
*文/CameloeAnthony(簡書作者)
原文鏈接:http://www.reibang.com/p/01d3c014b0b1
一闯袒、配置Dagger2虎敦。
1.在項目的gradle中加入apt的依賴
Paste_Image.png
2.在module的gradle中加入dagger2需要依賴的庫
Paste_Image.png
3.在module的gradle中加入插件支持
Paste_Image.png
4.如果已經(jīng)都配置好了,那么需要makeproject一下搁吓。
在AndroidStudio中原茅,點擊一下紅線標記的按扭
Paste_Image.png
二吭历、Dagger2的使用
圖片來自參考資料.png
1堕仔、既然是依賴注入,那么肯定有提供依賴的地方晌区,在Dagger2中提供依賴的類被標注為Module摩骨,在Module中,具體提供對象的方法朗若,被Provides注解標記恼五。
2、從流程圖中可以看出哭懈,Module中提供A對象給B和C灾馒。傳遞給B和C的工作由Component注解標記的接口來進行。
3遣总、在B和C哪個對象要通過注入拿到對象則通過Inject注解進行標示睬罗。
圖片來自參考資料
1.Inject注解
在Activity中轨功,為LogUtils加上Inject注解,告訴編譯器LogUtils需要通過注入的方式實例化容达。同樣可以使用@inject注解標注構(gòu)造方法古涧,方法等。
注意花盐,被inject標注的不能是private修飾的對象羡滑。
interface是不能被構(gòu)建的
第三方的類不能被注解
通過配置得到的對象,仍然必須通過配置得到(Builder模式構(gòu)造的對象)
如果使用@Inject標注了參數(shù)算芯,如果沒有通過Module提供依賴柒昏,會去查找是否有@Inject標注的構(gòu)造方法,
使用該構(gòu)造方法提供依賴熙揍,如果該構(gòu)造方法中也有參數(shù)昙楚,會去Module中查找是否提供了依賴。
Paste_Image.png
2.Module
Module是一個提供依賴對象的地方诈嘿,需要使用@Module標注類堪旧,使用@Provide標注提供依賴的方法
編譯器需要知道LogUtils的對象在哪里能夠得到。這時需要一個提供對象的類奖亚,加上Module注解
如果使用了@Scope注解為方法標注了使用的作用域淳梦,那么Component類上也需要有相應的作用域,否則編譯報錯昔字。
注意AppModuls的方法名是任意的爆袍,為了能更好的讀懂代碼一般都稱作provider+對象名稱。
Paste_Image.png
3.Component
1.有了提供的地方作郭,需要一個橋梁讓被標記為Inject的對象能夠拿到自己對應的對象陨囊,因為Moduls類只是提供不負責傳遞。所以需要一個Component接口夹攒,被標記為Component的類就是這個媒介蜘醋。
我們需要提供一個inject方法,并且參數(shù)一定要是對應的Activity咏尝,F(xiàn)ragment類压语,例如我在MainActivity中需要依賴注入,參數(shù)一定要為MainActivity编检,當然Component可以有多個inject方法胎食,為不同的頁面提供注入。
全局的AppComponent只能含有一個帶參的無返回值方法允懂,用來給對應的地方實行注入厕怜。如:
如果當前AppComponent被其他Component依賴了。其他Component提供依賴時,需要顯示的提供依賴粥航,即提返回對應依賴的無參方法舵揭。如:AppComponent
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(ContainerActivity activity);
Context getContext();
}
注意除了使用dependencies對當前的component進行擴展,還可以使用subcomponent進行擴展
@dependencies 代表需要哪一個component提供依賴
@module 代表通過哪一個module提供依賴躁锡。
如果你的module指定了作用域午绳,那么component也要使用相同的注解標定作用域
component支持多個module? 可以使用,號拼接映之,也可以使用下列寫法拦焚。
@Module(includes={ModuleA.class,ModuleB.class,ModuleC.class})
public class FruitModule{
...
}
@Component(modules={FruitModule.class}) //添加多個Module
public interface FruitComponent{
...
}
Paste_Image.png
4.在Application中將Component橋梁實例化
如果你的配置都正確,并且makeproject了杠输,編譯器會自動為你的Component生成代碼赎败,名稱是Dagger+你的Component名稱。如果沒有這個類蠢甲,請查看在Gradle中配置是否正確僵刮,并且是否makeproject了。
Paste_Image.png
5.Activity拿到中介(橋梁Component)鹦牛,為對象注入
提供的中介當然就是我們在Application中實例化的Component了搞糕。
Paste_Image.png
三、Component的之間的依賴---SubComponent
除了使用@Component的dependience注解擴展當前component的支持的依賴曼追,還可以通過SubComponent進行擴展窍仰,這有點像繼承關(guān)系。并且父Component不用顯示的拋出支持的依賴礼殊,只需添加一個返回子Component的方法
下面看一個來自于鴻洋Blog的圖片
http://chuansong.me/n/400687651115
使用@SubComponent標記子component
使用SubComponent進行擴展驹吮,父component顯示的拋出依賴,需要持有子component對象晶伦。
通過父Component拿到子Component
注意兩個地方
1.AppComponent 是根Component碟狞。
2.UserComponent 是子Component,UserComponent是通過appComponent得到婚陪。
這就是通過Component的相互依賴做到的族沃。
1、UserComponent
使用@Subcomponent標注
@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
AComponent plus(AModule aModule);
}
2近忙、父Component
提供子Component竭业。(返回值為子Component)
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
UserComponent plus(UserModule userModule);
}
三智润、@Name注解:區(qū)分不同對象的實例
該注解用來標識具體需要哪一個依賴及舍。因為往往我們想要的對象不只有一種依賴方式。例如我們需要一個網(wǎng)絡(luò)請求庫窟绷,可能有提供緩存的锯玛,可能不需要緩存,那么這個時候我們在Moudle中就會提供兩種依賴。具體選擇哪個則需要通過name標識去取攘残。
例如:
(http://www.reibang.com/writer#/notebooks/3267733/notes/4938210/preview)
1.Module提供兩種實例拙友。
@Provides @Named("cached")@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
OkHttpClient client = new OkHttpClient();
client.setCache(cache);
return client;
}
@Provides
@Named("non_cached")
@Singleton
OkHttpClient provideOkHttpClient() {
OkHttpClient client = new OkHttpClient();
return client;
}
2.根據(jù)需求選取不同的實例
@Inject @Named("cached") OkHttpClient cache_client;
@Inject @Named("non_cached") OkHttpClient non_cache_client;
@Qualifier注解
當然Dagger2通過使用@Qualifier可以定制自己的Name形式注解。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface UserNamed {
String value() default "";
}
這和Dagger2提供的name的代碼實現(xiàn)是一樣的
下面是Dagger2提供的name
http://chuansong.me/n/400687651115
Scope注解:用于限定范圍歼郭,指明Module可以像哪些對象提供依賴
1.定義自己Scope注解
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
2.在Module中加入Scope注解遗契,表示為哪些對象提供實例
鴻洋
3.在Component中加入Scope注解,表示在這個Component中病曾,有權(quán)利從Module中拿到被Scope標注的對象
@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
AComponent plus(AModule aModule);
BComponent plus(BModule bModule);
CComponent plus(CModule cModule);
}
參考資料
http://www.reibang.com/p/01d3c014b0b1
http://chuansong.me/n/400687651115
http://blog.csdn.net/study_zhxu/article/details/52169090
http://android.jobbole.com/82705/
http://gold.xitu.io/entry/572232fc1532bc00624b5c8e
http://codethink.me/2015/08/06/dependency-injection-with-dagger-2/非常簡潔清晰