依賴注入及Dagger2框架簡介

依賴注入簡介

在介紹Dagger框架之前我們先來看看依賴注入(Dependence Injection),依賴注入還有另一個名字叫控制反轉(Inversion of Control,英文縮寫為IoC),當你看到這兩個名詞時他們大多指的都是同一個概念(實際上依賴注入是控制反轉的一部分,其另一部分稱為依賴查找(Dependenc Lookup)使用相對較少且不在本文涉及范疇),那什么是依賴注入呢?依賴了什么?又注入了什么?

不懂的東西我們自然要去問谷哥和度娘了,我搜到了一篇文章講的還滿詳細的,大家可以去學習一下:依賴注入那些事兒,這篇文章雖然是基于c#語言寫的但是用在JAVA上也是絲毫沒有問題的。

在默認大家已經讀了上面那個鏈接里的文章N遍以后,我來用簡單的語言總結一下通常的代碼結構中,調用者會直接決定實現的方式,比如調用者需要一本書的實例,在初始化的時候就會決定這本書是語文書還是數學書。而在依賴注入的世界里調用者只會聲明我需要一本書,而在執行的時候才會根據外部條件決定給調用者語文書還是數學書。

無論你是否理解了依賴注入,我們先來看下依賴注入的優缺點(這些點可能部分和Dagger框架會不一致,僅供增進大家對依賴注入的理解):

優點:

  • 代碼分層:把邏輯分層后每層可以獨立的編寫和進行單元測試,而不用擔心影響到其他層的功能(只要不改變接口的實現)
  • 動態配置:通過XML等方式以及反射機制可以在運行時改變程序的行為而不必重新編譯代碼
  • 讓框架看起來更高端(這個是隨便BB的啦)

不足:

  • 生成一個對象的步驟變復雜了(事實上操作上還是挺簡單的),對于不習慣這種方式的人,會覺得有些別扭和不直觀。
  • 對象生成因為是使用反射編程,在效率上有些損耗。但相對于IoC提高的維護性和靈活性來說,這點損耗是微不足道的,除非某對象的生成對效率要求特別高。
  • 缺少IDE重構操作的支持,如果在Eclipse要對類改名,那么你還需要去XML文件里手工去改了,這似乎是所有XML方式的缺憾所在。

Dagger2框架簡介及實用

以下部分內容引用自詳解Dagger2

Dagger1簡介

有Dagger2自然就有Dagger1,先簡單說下Dagger1。Dagger1框架是由Square公司受到Guice啟發創建的,也是Android上最常用的依賴注入框架

Dagger1基本特點:

  • 多個注入點:依賴,通過injected
  • 多種綁定方法:依賴,通過provided
  • 多個modules:實現某種功能的綁定集合
  • 多個對象圖: 實現一個范圍的modules集合

Dagger1是在編譯的時候實行綁定,不過也用到了反射機制。但這個反射不是用來實例化對象的,而是用于圖的構成。Dagger會在運行的時候去檢測是否一切都正常工作,所以使用的時候會付出一些代價:偶爾會無效和調試困難。

詳細的細節我們就不多說了,這不是我們關注的重點。

Dagger2簡介

Dagger2是Dagger1的分支,由谷歌公司接手開發,目前的版本是2.0。Dagger2是受到AutoValue項目的啟發。 剛開始,Dagger2解決問題的基本思想是:利用生成和寫的代碼混合達到看似所有的產生和提供依賴的代碼都是手寫的樣子。

如果我們將Dagger2和1比較,他們兩個在很多方面都非常相似,但也有很重要的區別,如下:

  • 再也沒有使用反射:圖的驗證、配置和預先設置都在編譯的時候執行。
  • 容易調試和可跟蹤:完全具體地調用提供和創建的堆棧
  • 更好的性能:谷歌聲稱他們提高了13%的處理性能
  • 代碼混淆:使用派遣方法,就如同自己寫的代碼一樣

當然所有這些很棒的特點都需要付出一個代價,那就是缺乏靈活性,例如:Dagger2沒用反射所以沒有動態機制。

Dagger2簡單實用手冊

Dagger2的詳細官方文檔可以在這里找到:http://google.github.io/dagger/,本章基本源于對官方文檔的翻譯,加上了部分自己的想法幫助大家更快理解框架內容

整個Dagger2框架是依賴于Java語言的注解(Annotation)系統實現的,在分析Espresso源碼的過程中我們會遇到如下的注解:

  • @Inject
  • @Component
  • @Singleton
  • @Module
  • @Provides
  • @Subcomponent

@Inject注解

@Inject用于聲明依賴,在類的構造函數上使用@Inject注解,聲明該類可以被Dagger2實例化,同時如果該構造函數是帶參數的,那么就會去使用使用了@Inject聲明的構造函數生成一個實例傳遞進來。如示例代碼中heater就會調用new Heater()方法生成一個Heater實例注入進來(Heater()方法已有@Inject注解)。特別要提到的是沒有@Inject方法注解的類是無法被Dagger2框架實例化的:

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

也可以直接對成員變量注入

class CoffeeMaker {
  @Inject Heater heater;
  @Inject Pump pump;

  ...
}

@Provides注解滿足依賴

上文說到@Inject需要的依賴會自動調用構造方法,在有些情況下@Inject注解是無法生效的:

  • Interface是無法實例化的
  • 第三方庫是無法添加注解的
  • 需要配置的對象在給定配置前的實例化是沒有意義的

在這種情況下我們需要@Provides注解來滿足依賴,帶有這個注解的函數的返回類型就能滿足該類型所需的實例化依賴。舉個例子,前面的Heater()方法并沒有提供注入接口,那么當我們需要一個Heater對象時,如下的方法也能夠返回一個Heater對象:

@Provides Heater provideHeater() {
  return new ElectricHeater();
}

@Provides注解的方法也可以有自己的依賴,比如providePump方法就需要一個Thermosiphon類型的依賴:

@Provides Pump providePump(Thermosiphon pump) {
  return pump;
}

@Module注解依賴圖容器

@Provides不是隨處都能使用的,是需要在@Module注解標記的類內部才能生效的

@Module
class DripCoffeeModule {
  @Provides Heater provideHeater() {
    return new ElectricHeater();
  }

  @Provides Pump providePump(Thermosiphon pump) {
    return pump;
  }
}

@Component注解依賴圖的根節點

前面我們提到Dagger2框架會自動生成代碼來根據依賴圖產生類的實例,比如在示例代碼中:

@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
  CoffeeMaker maker();
}

@Component的modules參數聲明了依賴Module,同時聲明一個接口及接口方法,Dagger2框架會自動生成一個以Dagger為前綴的類繼承實現這個接口,在本例中生成的類會命名為DaggerCoffeeShop,并實現maker()方法,實現的方式是一個CoffeeMaker類型的依賴,即調用者可以使用DaggerCoffeeShop().maker()方法來獲得這個依賴。當然這個書寫是有點問題的,為了讓Dagger2框架幫我自動生成一個目標類的實例,需要調用create()方法,所以它的實現應該是這樣的:

public class CoffeeApp {
  public static void main(String[] args) {
    CoffeeShop coffeeShop = DaggerCoffeeShop.create();
    coffeeShop.maker();
  }
}

@Subcomponent子Component注解

在@Component注解的接口類的方法中,除了可以返回注入項(實現了@Inject注解的構造方法的類,可以被Dagger2框架實例化)類別以外,還可以返回@Subcomponent注解的子Component類,以實現多層調用的效果,具體請看Espresso源碼分析部分

@Singleton單例注解

這個注解是最好理解的,聲明了這個注解的實例在生成實例時都是單例化的,如果之前以及生成過改類型的實例會直接返回之前生成的實例而不是新建一個該類的新的對象

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容