Dagger2入門

1.Dagger2簡介

1.1 Dagger2的描述

Github地址:Dagger2

Dagger2官網上介紹是:A fast dependency injector for Android and Java.

Dagger2是提供給Android和Java使用的快速依賴注入框架,目的是為了解耦.

1.2 Dagger2的前世今生

Dagger2是由谷歌接手開發,最早版本的Dagger1 是由Square公司開發的.

相比于Dagger1,Dagger2有更好的性能,它使用的是預編譯期間生成代碼來完成依賴注入,而不像Dagger1那樣通過反射完成依賴注入;還有一點,因為Dagger2是使用生成代碼來實現依賴注入的,所以可以在相關代碼處下斷點進行調試.

1.3 Dagger2的用處

使用Dagger2最本質的目的是為了模塊間解耦,提供代碼的健壯性和可維護性.

舉個簡單的例子

public class A{

? ? B b;

? ? public A(){

? ? ? ? b = new B()

????}

}

如上代碼,在ClassA對ClassB有個依賴,如果某一天ClassB的創建方式發生改變,即構造方法發生改變,這時不僅要修改ClassB中的代碼,還需要在所有創建ClassB的類中進行修改,如上面的ClassA.

如果使用Dagger2的話,在ClassA中可以這樣寫:

public class A{

? ? @Inject

? ? B b;

}

此時不管B的創建方式如何修改,在ClassA中都不需要進行修改.


2.Dagger2的原理



如上圖所示:

最左邊,是提供依賴的部分,可以通過使用@Inject注解其構造方法或者在Module中使用@Provides注解提供.

中間部分是Component,它本質上是被@Component注解的接口,通過@Component注解與Module建立聯系,并提供inject()函數.它是一個橋梁,負責連接提供依賴的部分和需要依賴的部分,

最右邊是需要依賴的地方,使用@Inject注解變量,就可以創建它的對象.


3.Dagger2的使用

3.1 Android studio中配置

在工程的build.gradle文件中添加android-apt插件

dependencies {

? ? ?... // 其他classpath

? ? ?classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //添加apt命令

?}

module的build.gradle添加

apply plugin: 'com.neenbedankt.android-apt'//添加apt命令

dependencies {

? ? apt 'com.google.dagger:dagger-compiler:2.16' //指定注解處理器

? ? compile 'com.google.dagger:dagger:2.16' ?//dagger公用api

? ? provided 'org.glassfish:javax.annotation:10.0-b28' ?//添加android缺失的部分javax注解庫

}

但是當Android studio升級到3.0之后,就會出現以下錯誤:

Error:android-apt plugin is incompatible with the Android Gradle plugin. ?Please use 'annotationProcessor' configuration instead.

解決辦法:Studio升級到3.0之后原來的配置方式apt與最新版本Gradle已經不兼容,推薦使用annotationProcessor

只需要添加這三個依賴就可以,工程的build.gradle與app的build.gradle插件可不用添加

首先在Android studioModule的Gradle中添加如下代碼:

// Add Dagger dependencies

dependencies {

? compile 'com.google.dagger:dagger:2.16'

? annotationProcessor 'com.google.dagger:dagger-compiler:2.16'

?compile 'org.glassfish:javax.annotation:10.0-b28'?//添加android缺失的部分javax注解庫

}


3.2 常用注解

@Inject:

通常在需要依賴的地方使用這個注解。換句話說,你用它告訴Dagger這個類或者字段需要依賴注入。這樣,Dagger就會構造一個這個類的實例并滿足他們的依賴。

@Module:

Modules類里面的方法專門提供依賴,所以我們定義一個類,用@Module注解,這樣Dagger在構造類的實例的時候,就知道從哪里去找到需要的 依賴。modules的一個重要特征是它們設計為分區并組合在一起(比如說,我們的app中可以有多個組成在一起的modules)

@Provide:

在modules中,我們定義的方法是用這個注解,以此來告訴Dagger我們想要構造對象并提供這些依賴。

@Component:

Components從根本上來說就是一個注入器,也可以說是@Inject和@Module的橋梁,它的主要作用就是連接這兩個部分。

Components可以提供所有定義了的類型的實例,比如:我們必須用@Component注解一個接口然后列出所有所提供的依賴.

@Qualifier:

要作用是用來區分不同對象實例

@Named 其實是@Qualifier的一種實現


3.3 簡單示例

被需要依賴的類

public class AManager {

? ? public void makeShow() {

? ? ? ? Toast.makeText(AppUtils.getApp(), "Hello Dagger2!!!", Toast.LENGTH_SHORT).show();

? ? }

}

提供依賴的類:Module

@Module

public class ManagerModule { ? ?

? ? @Provides

? ? public AManager provideManagerA(String name) {

? ? ? ? Log.e("TAG", "provideManagerA");

? ? ? ? return new AManager();

? ? }

}

中間橋梁:Contenent

@Component(modules = {ManagerModule.class})

public interface ManagerComponent {

? ? void inject(MainActivity activity);

}

需要依賴的類:Container

public class MainActivity extends AppCompatActivity {

? ? @Inject

? ? AManager aManager;

? ? @Override

? ? protected void onCreate(Bundle savedInstanceState) {

? ? ? ? super.onCreate(savedInstanceState);

? ? ? ? setContentView(R.layout.activity_main);

? ? ? ? DaggerManagerComponent.create().inject(this);

? ? ? ? findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onClick(View view) {

? ? ? ? ? ? ? ? aManager.makeShow();

? ? ? ? ? ? }

? ? ? ? });

? ? }

}

3.4 關于模塊化的實現

在項目中,出于更加靈活以及可維護等其他原因,常進行模塊化的劃分,比如B功能的實現需要A,C功能的實現也需要A,那么我們就需要單獨對A進行處理,以便于其他功能模塊的使用.

Dagger有三種途徑進行模塊之間的依賴:

方式一:Module中通過@Module注解,includes其他的Module

@Module(includes = {xxxModule.class})

方式二:Component中通過@Component注解關聯需要的其他Module

@Component(modules = {ManagerModule.class,xxxxModule.class})

方式三:Component中通過@Component注解dependencies 其他Component

@Component(modules = {ManagerModule.class},dependencies = {xxxComponent.class})

注意事項:

通過方式三與其他模塊關聯時,被需要依賴的類的構造方法需要使用@Inject進行注解,同時在注入Container的時候把其他的Component進行注入.

3.5 創建和區分不同實例

>>>>>>>方式一:使用@Named注解

@Module

public class ManagerBModule {

? ? @Named("release")

? ? @Provides

? ? public BManager provideManagerB_Release(AManager aManager) {

? ? ? ? BManager bManager = new BManager(aManager);

? ? ? ? Log.e("TAG", "provideManagerB_Release:" + bManager);

? ? ? ? return bManager;

? ? }

? ? @Named("debug")

? ? @Provides

? ? public BManager provideManagerB_Debug(AManager aManager) {

? ? ? ? BManager bManager = new BManager(aManager);

? ? ? ? Log.e("TAG", "provideManagerB_Debug:" + bManager);

? ? ? ? return bManager;

? ? }

}

? ? @Named("release")

? ? @Inject

? ? BManager bManager_release;


? ? @Named("debug")

? ? @Inject

? ? BManager bManager_debug;


>>>>>>>方式二:使用自定義注解

模仿Named注解,進行自定義

自定義Release注解:

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface Release {

}

自定義Debug注解:

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface Debug {

}

在Module中使用:

@Module

public class ManagerBModule {

? ? @Release

? ? @Provides

? ? public BManager provideManagerB_Release(AManager aManager) {

? ? ? ? BManager bManager = new BManager(aManager);

? ? ? ? Log.e("TAG", "provideManagerB_Release:" + bManager);

? ? ? ? return bManager;

? ? }


? ? @Debug

? ? @Provides

? ? public BManager provideManagerB_Debug(AManager aManager) {

? ? ? ? BManager bManager = new BManager(aManager);

? ? ? ? Log.e("TAG", "provideManagerB_Debug:" + bManager);

? ? ? ? return bManager;

? ? }

}

在Activity中的使用:

? ? @Release

? ? @Inject

? ? BManager bManager_release;


? ? @Debug

? ? @Inject

? ? BManager bManager_debug;


3.6 Singleton單例講解

使用@Singleton注解,需要注意的是如果Module中,@Provides注解的方法使用了@Singleton注解,那么與之對應的Component也要加上@Singleton注解.

Module代碼:

Component代碼:

Activity代碼:

點擊按鈕后的Log日志:

注意事項:

Dagger2中的單例與Java中的單例不同,Java中的單例對象是存放在靜態區的,而Dagger2的單例是與Component相關聯的.不同Component所提供的實例化的單例對象是不同的.

3.7關于自定義Scope

由于component的dependencies與component自身的scope不能相同,即組件之間的scope不同,因此需要自定義一些Scope

對于應用級的AppComponent常使用@Singleton,以使某些對象在整個程序中只實例化一次

Module:

AppModule

Component:

AppComponent


Application:

Application


自定義的ActivityScope

ActivityScope

依賴AppComponent的Component:

依賴AppComponent的Component

Activity代碼:

Activity代碼

關于Scope推薦一篇文章:Dagger2Scope講解

有關Scope注解參照@Singleton注解

@Scope :注明是Scope ,表示作用域范圍

@Documented :標記在文檔

@Retention(RUNTIME) :運行時級別

Scope的生命周期是依附于其容器的,當其所依附的Application或者是Activity銷毀后,其關聯的Module中的實例化對象也會被銷毀.


3.8關于Subcomponent

在Dagger2中,Component之間存在兩種關系,依賴關系和繼承關系

依賴關系:一個 Component 依賴其他 Component 公開的依賴實例,使用 @Component 注解中的dependencies進行聲明.

繼承關系:一個 Component 繼承某個Component 提供更多的依賴,SubComponent 就是繼承關系的體現.

兩者之間的比較:

>相同點:

? ??兩者都能復用其他 Component 的依賴

????有依賴關系和繼承關系的 Component 不能有相同的 Scope

>不同點:

? ? ? 依賴關系中被依賴的 Component 必須顯式地提供公開依賴實例的接口,而 SubComponent 默認繼承 parent Component 的依賴.

? ? ? 依賴關系會生成兩個獨立的 DaggerXXComponent 類,而 SubComponent 不會生成 獨立的 DaggerXXComponent 類.

示例:

父Component的Module:

父Component:

子Component的Module相關:

工具類
子ComponentModule類

子Component:

Activity代碼:

注意事項:

1>Subcomponent同時具備兩種不同生命周期的scope, SubComponent具備了父Component擁有的Scope,也具備了自己的Scope.

2>SubComponent的Scope范圍小于父Component


3.9拓展-關于Lazy與Provider:

Lazy(延時注入):

有時當需要注入的依賴在使用時再完成初始化,加快加載速度,就可以使用注入Lazy<T>.只有在調用 Lazy 的 get() 方法時才會初始化依賴實例注入依賴.

好比component初始化了一個present對象,然后放到一個池子里,需要的時候就get它,所以你每次get的時候拿到的對象都是同一個;并且當你第一次去get時,它才會去初始化這個實例.

provider(強制加載):

有時候不僅僅是注入單個實例,我們需要多個實例,這時可以使用注入Provider<>,每次調用它的 get() 方法都會調用到?@Inject 構造函數創建新實例或者 Module 的 provide 方法返回實例。

注意事項:

要想調用Porvder的get()到的實例對象不同,必須其Module中提供實例的方法沒有被@Scope注解,不然所獲取到的是同一對象.

4 注意事項

1. Component 的 inject(自定義,可以隨便起名) 方法如果接收的是父類型參數,而調用時傳入的是子類型對象則無法實現注入;

2. Component中使用@Component注解關聯的modules中的Module內不能有重復的provide,除非使用@Qualifier注解進行限定,如@Named注解;

3. Module的@Provides注解的方法使用了 Scope ,那么與其關聯的Component 就必須使用同一個Scope注解;如果Module中@Provides注解的方法沒有使用Scope,那么與其關聯的Component是否加Scope注解都無所謂,可以通過編譯;

4.Component中使用@Component注解聲明的dependencies與Component自身的Scope不能相同,即組件之間的Scope必須不同;

5.@Singleton注解的組件不能依賴其他Scope的組件,只能其他Scope的組件依賴Singleton的組件;

6.沒有Scope的Component不能依賴有Scope的Component;

7.一個Component不能同時有多個scope(Subcomponent除外);

8.@Singleton 的生命周期依附于Component,同一個Module provide singleton實例對象 ,不同Component 也是不一樣的;

9.已使用Component注入的Container不能被其他Component二次注入.









?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 巴娜娜是一只2014年12月30日出生的小薩摩。 它的媽媽是我同學的狗狗,名叫憨憨。 狗爸爸也是只純薩摩。 巴娜娜...
    凌雪懿閱讀 501評論 0 3
  • 可以輸入
    dfd48e1e3fea閱讀 192評論 0 1
  • 焦點網絡初級 程玲玲 鄭州 堅持分享第127天 出軌路線圖:從可能到事實 通常,長期且有承諾關系的伴侶會在他們和世...
    思小念052閱讀 303評論 0 0