配置Dagger2
參考Dagger2 Wiki笋轨,在Gradle中添加以下依賴
dependencies {
provided 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.dagger:dagger:2.0.2'
apt 'com.google.dagger:dagger-compiler:2.0.2'
}
apt
是一個(gè)Gradle插件秆剪,協(xié)助Android Studio 處理Annotation Processors
,所以在Gradle中還必須添加以下內(nèi)容(關(guān)于Android-apt
更多內(nèi)容參考)
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
apply plugin: 'com.neenbedankt.android-apt'
開(kāi)始使用
Dagger2是實(shí)現(xiàn)依賴注入
的一種手段爵政,關(guān)于依賴注入仅讽,這里就不多介紹,想了解的可以參考, Dagger2中需要使用注解來(lái)完成依賴注入钾挟,我們來(lái)一個(gè)個(gè)介紹這些注解
@Inject
我們可以使用@Inject
這個(gè)注解來(lái)標(biāo)注目標(biāo)類中所依賴的其他類洁灵,也可以用來(lái)標(biāo)注所依賴的其他類的構(gòu)造函數(shù)。舉個(gè)例子
public class Human{
@Inject
Father father;
}
public class Father{
@Inject
public Father(){ //如果標(biāo)注有參數(shù)的構(gòu)造方法掺出,在調(diào)用構(gòu)造方法前會(huì)去獲取參數(shù)對(duì)應(yīng)的對(duì)象
}
}
當(dāng)Human
需要通過(guò)@Inject
注入Father
這個(gè)類的時(shí)候徽千,會(huì)先調(diào)用Father
中標(biāo)注的構(gòu)造函數(shù),生成相應(yīng)的對(duì)象汤锨。這樣Human
和Father
之間就有了一種無(wú)形的聯(lián)系罐栈,但是僅僅這樣還不夠,我們還需要用到Component
來(lái)使他們連接起來(lái)
@Component
@Component
的作用就是連接目標(biāo)類和目標(biāo)類依賴實(shí)例(可以通過(guò)上面說(shuō)的@Inject
標(biāo)注構(gòu)造函數(shù)也可以通過(guò)@Module
來(lái)產(chǎn)生)泥畅。那Component
是怎么工作的呢荠诬?
查找目標(biāo)類中用
@Inject
標(biāo)注的屬性查找對(duì)應(yīng)屬性依賴實(shí)例
將依賴實(shí)例進(jìn)行賦值
目標(biāo)類需要初始化自己依賴的其他類還需要調(diào)用Component
的inject(Object object)方法開(kāi)始注入
@Singleton @Component(modules = { ApplicationModule.class},dependencies={xxxComponent.class})
public interface ApplicationComponent {
Context getContext();
void inject(MyApplication mApplication);
}
比如在MyApplication
中需要注入其他類琅翻,則需要在MyApplication
中調(diào)用ApplicationComponent
的inject
方法開(kāi)始注入。
-
modules
對(duì)應(yīng)的就是提供依賴的Module
類柑贞,可以有多個(gè) -
dependencies
表示該Component還依賴其他Component -
@Singleton
是一種Scope
注解方椎,下面會(huì)說(shuō)到
@Module
介紹@Inject
的時(shí)候我們說(shuō)過(guò),可以通過(guò)@Inject
標(biāo)注構(gòu)造函數(shù)生成對(duì)應(yīng)的對(duì)象钧嘶,但是如果是第三方類庫(kù)棠众,我們無(wú)法添加@Inject
注解的時(shí)候該怎么辦,這時(shí)候就需要用到@Module
了有决。舉個(gè)列子
@Module
public class Module{
//A是第三方類庫(kù)中的一個(gè)類
@Provides
A provideA(){
return A();
}
}
通過(guò)
provideA()
這個(gè)方法我們就可以生成一個(gè)A
的實(shí)例闸拿,目標(biāo)類中可以通過(guò)@Inject
來(lái)注入@provides
標(biāo)注的方法直接返回以創(chuàng)建或者新創(chuàng)建的對(duì)象,只在Module
中使用Component
會(huì)首先從Module
中查找需要注入的實(shí)例书幕,如果找到了新荤,則停止,如果沒(méi)有找到則是繼續(xù)從Inject
標(biāo)注的構(gòu)造函數(shù)查找
@Qualifier
通過(guò)上面我們知道台汇,創(chuàng)建類的實(shí)例有兩種方式苛骨,這兩個(gè)方式有先后之分,但是如果一個(gè)類在同一方式下有多個(gè)創(chuàng)建類的方法的時(shí)候苟呐,Component
會(huì)選取哪個(gè)方法來(lái)創(chuàng)建這個(gè)類的實(shí)例呢痒芝?舉個(gè)例子
@Module
public class Module{
@Provides
A provideA(){
return A();
}
@provides
A provideOtherA(){
return A();
}
}
如果我們按照上面這樣寫(xiě),Dagger2在編譯的時(shí)候就會(huì)報(bào)錯(cuò)牵素,那么我們改如何解決呢严衬?這時(shí)候就需要用到@Qualifier
了,我們可以用這個(gè)注解給不同的創(chuàng)建實(shí)例的方法進(jìn)行標(biāo)識(shí)并加以區(qū)分笆呆。
@Module
public class Module{
@Named("firstA")
@Provides
A provideFirstA(){
return A();
}
@Named("secondA")
@provides
A provideSecondA(){
return A();
}
}
@Named
是Dagger2對(duì)于@Qualifier
一個(gè)默認(rèn)實(shí)現(xiàn)瞳步,我們也可以自定義,比如@ForApplication
和@ForAcitivity
來(lái)標(biāo)識(shí)不同的Context
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}
這樣腰奋,通過(guò)@Named
我們就可以區(qū)分不同的實(shí)例了
public class Human{
@Inject
@Named("firstA")
A firstA;
@Named("secondA")
@provides
A secondA;
}
@Scope
Scope
是一個(gè)注解作用域单起,通過(guò)自定義注解限定對(duì)象的作用范圍。通過(guò)這個(gè)注解能夠解決不同對(duì)象生命周期不一致的問(wèn)題劣坊,比如Application
,ToastHelper
等存在于應(yīng)用的整個(gè)生命周期嘀倒,Adapter
,Presenter
等則隨著Activity的銷毀而銷毀。我們可以通過(guò)自定義不同的Scope
來(lái)區(qū)分局冰。舉個(gè)例子
@Scope
@Documented
@Retention(RUNTIME)
public @interface PerApp{}
@PerApp @Component(modules = { ApplicationModule.class})
public interface ApplicationComponent {
Context getContext();
void inject(MyApplication mApplication);
}
@Module
public class ApplicationModule {
private final Context context;
public ApplicationModule(Context context) {
this.context = context;
}
@Provides @PerApp public Context provideApplicationContext() {
return context.getApplicationContext();
}
}
我們?cè)?code>ApplicationModule中定義了創(chuàng)建Context
實(shí)例的方法测蘑,在ApplicationComponent
中管理ApplicationModule
,因?yàn)?code>ApplicationComponent只有在Application
中實(shí)例化一次康二,所以Context
的生命周期也就和Application
一樣了碳胳,也就是Dagger
并不會(huì)幫你管理生命周期,只能自己來(lái)控制沫勿。那么PerApp
這個(gè)注解有什么用呢挨约?
- 更好的管理
Component
與Module
之間的匹配關(guān)系味混,Dagger2在編譯的時(shí)候會(huì)檢查Component
管理的Module
,若發(fā)現(xiàn)Component
所標(biāo)注的自定義Scope
注解與Module
中不一樣诫惭,就會(huì)報(bào)錯(cuò)翁锡。 - 提高可讀性,通過(guò)
PerApp
就知道是在整個(gè)Application
有小范圍內(nèi)
注意點(diǎn):
- 一個(gè)
Module
中只能存在一種Scope
-
Scope
標(biāo)注的Component
和所依賴的Component
的Scope
不能一樣
實(shí)例講解
創(chuàng)建ApplicationComponent
@PerApp
@Component(modules = { ApplicationModule.class })
public interface ApplicationComponent {
Context getContext();
ToastUtils getToastUtils();
}
ApplicationComponent
是一個(gè)全局的Component
,負(fù)責(zé)管理整個(gè)App的全局類實(shí)例,Context getContext();
和ToastUtils getToastUtils();
是將Context
和ToastUtils
暴露給子Component夕土。
創(chuàng)建ApplicationModule
@Module
public class ApplicationModule {
private final MyApplication myApplication;
public ApplicationModule(MyApplication myApplication) {
this.myApplication = myApplication;
}
@PerApp @Provides Context provideContext() {
return myApplication.getApplicationContext();
}
@PerApp @Provides ToastUtils provideToastUtils(Context mContext) {
return new ToastUtils(mContext);
}
}
ApplicationModule
生成全局Context
和ToastUtils
實(shí)例
在Application中創(chuàng)建ApplicationComponent實(shí)例
public class MyApplication extends Application {
private ApplicationComponent mApplicationComponent;
@Override public void onCreate() {
super.onCreate();
mApplicationComponent =
DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
}
public ApplicationComponent getApplicationComponent() {
return mApplicationComponent;
}
}
DaggerApplicationComponent
這個(gè)是有Dagger2生成的類馆衔,因?yàn)?code>ApplicationComponent只初始化一次,所以注入的類都是單例的怨绣,這就是Dagger2真正創(chuàng)建單例的方法角溃。
劃分Component
一個(gè)應(yīng)用應(yīng)該包含一個(gè)全局的Component
,負(fù)責(zé)管理整個(gè)全局類的實(shí)例篮撑,其他Componet建議按照頁(yè)面來(lái)劃分减细。
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = {
MainModule.class, ActivityModule.class
})
public interface MainComponent {
void inject(MainActivity mActivity);
}
@Module
public class MainModule {
@PerActivity @Provides GetUser getUser() {
return new GetUser();
}
}
@PerActivity
@Component(modules = { ActivityModule.class })
public interface ActivityComponent {
Activity getActivity();
}
@Module
public class ActivityModule {
private final Activity mActivity;
public ActivityModule(Activity mActivity) {
this.mActivity = mActivity;
}
@Provides @PerActivity Activity provideActivity() {
return mActivity;
}
}
上面是Main
這個(gè)頁(yè)面的劃分