Linux中國

安卓平台上的依賴注入(一)

剛開始學習軟體工程的時候,我們經常會碰到像這樣的事情:

軟體應該符合 SOLID 原則。

但這句話實際是什麼意思?讓我們看看 SOLID 中每個字母在架構里所代表的重要含義,例如:

簡單來說,我們需要提供一個類,這個類有它所需要的所有對象,以便實現其功能。

概述

依賴注入聽起來像是描述非常複雜的東西的一個術語,但實際上它很簡單,看下面這個例子你就明白了:

class NoDependencyInjection {
  private Dependency d;

  public NoDependencyInjection() {
    d = new Dependency();
  }
}

class DependencyInjection {
  private Dependency d;

  public DependencyInjection(Dependency d) {
    this.d = d;
  }
}

正如我們所見,第一種情況是我們在構造器里創建了依賴對象,但在第二種情況下,它作為參數被傳遞給構造器,這就是我們所說的 依賴注入 dependency injection 。這樣做是為了讓我們所寫的類不依靠特定依賴關係的實現,卻能直接使用它。

參數傳遞的目標是構造器,我們就稱之為構造器依賴注入;或者是某個方法,就稱之為方法依賴注入:

class Example {
  private ConstructorDependency cd;
  private MethodDependency md;
  Example(ConstructorDependency cd) {
    this.cd = cd; //Constructor Dependency Injection
  }

  public setMethodDependency(MethodDependency md) {
    this.md = md; //Method Dependency Injection
  }
}

要是你想總體深入地了解依賴注入,可以看看由 Dan Lew 發表的精彩的演講,事實上是這個演講啟迪了這篇概述。

在 Android 平台,當需要框架來處理依賴注入這個特殊的問題時,我們有不同的選擇,其中最有名的框架就是 Dagger 2。它最開始是由 Square 公司(LCTT 譯註:Square 是美國一家移動支付公司)的一些很棒的開發者開發出來的,然後慢慢發展成由 Google 自己開發。首先開發出來的是 Dagger 1,然後 Big G 接手這個項目發布了第二個版本,做了很多改動,比如以 註解 annotation 為基礎,在編譯的時候完成其任務。

導入框架

安裝 Dagger 並不難,但需要導入 android-apt 插件,通過向項目的根目錄下的 build.gradle 文件中添加它的依賴關係:

buildscript{
  ...
  dependencies{
    ...
    classpath 『com.neenbedankt.gradle.plugins:android-apt:1.8』
  }
}

然後,我們需要將 android-apt 插件應用到項目 build.gradle 文件,放在文件頂部 Android application 那一句的下一行:

apply plugin: 『com.neenbedankt.android-apt』

這個時候,我們只用添加依賴關係,然後就能使用庫及其 註解 annotation 了:

dependencies{
    ...
    compile 『com.google.dagger:dagger:2.6』 
    apt 『com.google.dagger:dagger-compiler:2.6』
    provided 『javax.annotation:jsr250-api:1.0』
}

需要加上最後一個依賴關係是因為 @Generated 註解在 Android 里還不可用,但它是原生的 Java 註解

Dagger 模塊

要注入依賴,首先需要告訴框架我們能提供什麼(比如說上下文)以及特定的對象應該怎樣創建。為了完成注入,我們用 @Module 注釋對一個特殊的類進行了註解(這樣 Dagger 就能識別它了),尋找 @Provide 註解的方法,生成圖表,能夠返回我們所請求的對象。

看下面的例子,這裡我們創建了一個模塊,它會返回給我們 ConnectivityManager,所以我們要把 Context 對象傳給這個模塊的構造器。

@Module
public class ApplicationModule {
  private final Context context;

  public ApplicationModule(Context context) {
    this.context = context;
  }

  @Provides @Singleton
  public Context providesContext() {
    return context;
  }

  @Provides @Singleton
  public ConnectivityManager providesConnectivityManager(Context context) {
    return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  }
}

Dagger 中十分有意思的一點是簡單地註解一個方法來提供一個單例(Singleton),就能處理所有從 Java 中繼承過來的問題。

組件

當我們有一個模塊的時候,我們需要告訴 Dagger 想把依賴注入到哪裡:我們在一個 組件 Component 里完成依賴注入,這是一個我們特別創建的特殊註解介面。我們在這個介面里創造不同的方法,而介面的參數是我們想注入依賴關係的類。

下面給出一個例子並告訴 Dagger 我們想要 MainActivity 類能夠接受 ConnectivityManager(或者在圖表裡的其它依賴對象)。我們只要做類似以下的事:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

  void inject(MainActivity activity);
}

正如我們所見,@Component 註解有幾個參數,一個是所支持的模塊的數組,代表它能提供的依賴。這裡既可以是 Context 也可以是 ConnectivityManager,因為它們在 ApplicationModule 類中有聲明。

用法

這時,我們要做的是儘快創建組件(比如在應用的 onCreate 階段)並返回它,那麼類就能用它來注入依賴了:

為了讓框架自動生成 DaggerApplicationComponent,我們需要構建項目以便 Dagger 能夠掃描我們的代碼,並生成我們需要的部分。

MainActivity 里,我們要做的兩件事是用 @Inject 註解符對想要注入的屬性進行註解,調用我們在 ApplicationComponent 介面中聲明的方法(請注意後面一部分會因我們使用的注入類型的不同而變化,但這裡簡單起見我們不去管它),然後依賴就被注入了,我們就能自由使用他們:

public class MainActivity extends AppCompatActivity {
  @Inject
  ConnectivityManager manager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    ((App) getApplication()).getComponent().inject(this);
  }
}

總結

當然了,我們可以手動注入依賴,管理所有不同的對象,但 Dagger 消除了很多比如模板這樣的「雜訊」,給我們提供有用的附加品(比如 Singleton),而僅用 Java 處理將會很糟糕。

via: https://medium.com/di-101/di-101-part-1-81896c2858a0#.3hg0jj14o

作者:Roberto Orgiu 譯者:GitFuture 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國