1. 程式人生 > >Dagger學習 -- 基礎概念

Dagger學習 -- 基礎概念

Dagger 依賴註入 模塊化 解耦

目標

了解 Dagger 基本概念

官方定義

Google 對 Dagger 的定義如下:

Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier version created by Square and now maintained by Google.

Dagger 是一個為 Java 和 Android 設計的完全靜態,編譯時依賴註入框架。現在由 Google 維護,它對 Square 開發的早期版本進行了改寫。

什麽是編譯時依賴呢?就是不在運行時依賴,額...Dagger 會通過註解,生成代碼,而這個代碼跟我們手動寫的依賴註入的代碼一樣。

如果你對『依賴註入』不了解,請看[這篇文章]()(未填的坑)。

Dagger1.x已經廢棄,我們以後所說的Dagger就是Dagger2.x。

Dagger 原理

Dagger 使用了註解,我們先來最基本的註解的用法。

聲明依賴 @Inject

Dagger 使用註解 javax.inject.Inject 來修飾一個類的構造函數,然後就 Dagger 就可以管理它了。當 Dagger 需要 該類的實例時,就會調用這個構造函數來構造它,也會自動實例化該構造函數的參數所需要的實例。

@Inject 也可以修飾一個類的屬性,在構造這個類時,Dagger 會將這個屬性所需要的對象實例化出來。但是要註意,這個屬性的類型構造函數需要註入即也用 @Inject 修飾。

@Inject 還可以修飾一個方法,這樣在構造實例後,會立刻調用該方法。並不推薦這樣做,因為這就是初始化的工作嘛,都可以在構造函數裏做。

class Thermosiphon implements Pump {
  private final Heater heater;

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

  ...
}

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

  ...
}

但是 @Inject 有他的局限性

  1. 接口不能註入,它沒有構造函數。而一個好的設計是面向接口編程
  2. 第三方類庫的類,我們不能修改,沒法給它加 @Inject
  3. 我們需要的對象可能需要配置,而且每次需要的配置可能還不同

滿足依賴 @Provides

以上 @Inject 的問題都可以通過 @Provides 來解決。 @Provides 修飾一個方法,這個方法會提供一個對象,在方法裏我們自己實現如何實例化一個對象,如何配置。這個方法也可以有參數,同 @Inject 修飾的構造函數,參數會被註入。

但是,@Inject 修飾的方法只能是一個 Module 的方法可以是靜態的或者非靜態的。而這個 Module 實際只是一個由 @Module 修飾的普通的類。

約定,@Provides 修飾的方法命名以 provide 開頭,@Module 修飾的類以 Module 結尾。

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

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

構建對象圖

@Inject 和 @Provides 修飾的類組成了一個對象圖,而其中的元素因依賴而連接。而應用的入口點,就需要拿到這個圖的一個根的集合(這牽扯到數據結構了,數據結構裏的樹有一個根,而圖可以有多個根,從這個根,連接到一系列節點構成一顆樹)。Dagger 通過 Component 提供這個圖的根的集合。只有拿到 Component, Dagger 才能按照約定構造所有依賴的實例。

Component 是一個 @Component 修飾的接口,它定義一系列無參數方法,返回需要的類型。Dagger 會生成它的實現類,該類命名是在接口名前加 Dagger(如果你是用的Android Studio,要點編譯按鈕後才會生成實現類)。

@Component 註解還可以傳一個參數,modules,即該 Component 所依賴的 Module

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

在應用的入口點,通過 Component 的 builder 構造 Component 的實例,需要手動創建一個 Module 的實例。

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
    .dripCoffeeModule(new DripCoffeeModule())
    .build();

總結

我們一塊學習了 Dagger 中最基本的概念:

  1. @Inject 聲明依賴
  2. @Provides 我們自定義如何提供一個實例
  3. @Module 修飾一個類,它內部可以定義多個 @Provides 修飾的方法
  4. @Component 修飾一個接口,它定義了依賴形成的圖的一系列根。啟動這個構造系統的導火索。

本文主要參考了,Dagger 官方文檔。

Dagger學習 -- 基礎概念