Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Dagger依賴注入框架淺析

Android Dagger依賴注入框架淺析

編輯:關於Android編程

今天接觸了Dagger這套android的依賴注入框架(DI框架),感覺跟Spring 的IOC差不多吧。這個框架它的好處是它沒有采用反射技術(Spring是用反射的),而是用預編譯技術,因為基於反射的DI非常地耗用資源(空間,時間)

由於現在開發都是用Android Studio了,所以我這裡大概講下配置Dagger框架的開發環境,需要怎麼做。

(由於Android Studio中用Gradle,所以跟傳統我們用Eclipse配置的話,直接導入jar包,有點不一樣。)


在開始看我的博文前,希望大家有時間可以自己看下Dagger官網的文檔:http://square.github.io/dagger/

對應的中文翻譯:http://fanxu.me/post/2013-07-18#main(主要就是這篇文章翻譯得很詳細,就是太長了,我主要對這文章進行了自己的理解還有自己的淺析哈,所以如果你時間充裕,並且足夠耐心,可以先看這個!)


Dagger是構建在Android annotations的基礎上的,如果你還不知道關於Android annotations,可以先看看我之前的一篇文章。


Android annotations淺析:http://blog.csdn.net/ljphhj/article/details/37601173


一、Android Studio 配置 Dagger 開源框架環境

1、建立一個module

2、在module中會有build.gradle的文件

3、在文件中的下列位置加入兩行紅色字體

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:19.+'
compile 'com.squareup.dagger:dagger:1.2.+'
provided 'com.squareup.dagger:dagger-compiler:1.2.+'

}


二、Dagger淺析

1、任何新生事物的產生都有其特定的歷史背景,為什麼會出現Dagger框架呢?

Dagger框架為了簡化你的代碼,讓你把你的注意力轉移到真正需要關注的類上,比如:

我們常說要通過工廠類來創建出產品類對象。但是,往往我們更重視的是產品類,而並不是工廠類,更不是它的生產過程。


2、Dagger框架怎麼用?


Dagger框架圖:

\


首先我要用大白話的形式讓大家明白幾個概念:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD48cD4o0tTPwsDgyei8xs60sdi6z8Dto6zWu86qwcvIw7TzvNK4/LrDtdjA7b3iKTwvcD48cD48YnIgLz48L3A+PHA+MS5ASW5qZWN016LI67bUz/M8L3A+PHA+cHVibGljIGNsYXNzIDxzdHJvbmc+Q2xhc3NSb29tPC9zdHJvbmc+ezwvcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz4JQEluamVjdCA8L3N0cm9uZz5TdHVkZW50IHN0dWRlbnQxOyAvL7zTyc/V4rj216K94kBJbmplY3SjrCCx7cq+tbHHsMDgQ2xhc3NSb29t0qrXosjr1eLR+dK7uPbA4FN0dWRlbnS1xLbUz/M8L3A+PHA+CS8vtavKx77TyLvO0seww+bLtURhZ2dlcrK7ysfNqLn9t7TJ5Lv61sajrLb4ysfUpLHg0uu1xLy8yvWjrMTHw7TL/NKqPHN0cm9uZz7U9cO01qq1wFN0dWRlbnTA4LbUz/PTycutzOG5qbP2wLTE2KO/PC9zdHJvbmc+PC9wPjxwPjxiciAvPjwvcD48cD59IDwvcD48cD48YnIgLz48L3A+PHA+Mi7TydPa16LI67bUz/PDu9PQ0ru49szhuam21M/ztcS12Le9yseyu7/J0tS1xKOsy/nS1NL9s/bBy0BQcm92aWRlc9eiveIsILrNIEBNb2R1bGW1xLjFxO48L3A+PHA+PGJyIC8+PC9wPjxwPi8v08nT2kBQcm92aWRlc9KqsPy6rNTaQE1vZHVsZdeiys21xMDg1tCjrMv50tTWu9Kquq/K/dbQs/bP1sHLQFByb3ZpZGVzvs2x2NDr0qrU2sDgyc/D5rzTyc9ATW9kdWxl16K94jwvcD48cD48c3Ryb25nPkBNb2R1bGU8L3N0cm9uZz48L3A+PHA+cHVibGljIGNsYXNzIDxzdHJvbmc+U3R1ZGVudE1vZHVsZTwvc3Ryb25nPns8L3A+PHA+CSAgLy+808nPwctAUHJvdmlkZXO1xLe9t6ijrERhZ2dlcrvhyKXKtrHwy/y1xLe1u9jA4NDNo6y1sbeiz9bL/LXEt7W72MDg0M3Kx1N0dWRlbnTA4KOsyc/D5rXa0ruyvbXEQEluamVjdL7Nu+HAtLX308PL/CzN6rPJ16LI66GjPC9wPjxwPgk8c3Ryb25nPkBQcm92aWRlcyBTdHVkZW50IDwvc3Ryb25nPnByb3ZpZGVTdHVkZW50KCl7PC9wPjxwPgkJcmV0dXJuIG5ldyBTdHVkZW50KCk7PC9wPjxwPgl9PC9wPjxwPjwvcD48cD59PC9wPjxwPjxlbT48c3Ryb25nPtS8tqhAUHJvdmlkZXO6r8r90tRwcm92aWRl1/fOqsew17qjrCBATW9kdWxlwODS1E1vZHVsZdf3zqq689e6oaM8L3N0cm9uZz48L2VtPjwvcD48cD48YnIgLz48L3A+PHA+yOe5+9LUyc+1xMTjtrzA7b3iwcujrMTHw7S908/CwLS1xLartqu+zbrDsOzBy6Oho6E8L3A+PHA+PGJyIC8+PC9wPjxwPjMutbHO0sPHz6PN+7K7udy24MnZuPa12Le916LI61N0dWRlbnTV4rj2wOCjrM7Sw8fWu8+jzfvTtdPQ0ru33aGwU3R1ZGVudKGxtcTKtcD9ttTP86OotaXA/aOpo6zEx8O0ztLDx7/J0tTTw7W916K94kBTaW5nbGV0b24gvNPU2iBAUHJvdmlkZXPXor3itcS688PmvLS/yTwvcD48cD48YnIgLz48L3A+PHA+PC9wPjxwPjxzdHJvbmc+QFByb3ZpZGVzIEBTaW5nbGV0b24gPC9zdHJvbmc+U3R1ZGVudCBwcm92aWRlU3R1ZGVudCgpezwvcD48cD4JcmV0dXJuIG5ldyBTdHVkZW50KCk7PC9wPjxwPn08L3A+PHA+PGVtPjxzdHJvbmc+QFNpbmdsZXRvbiDXosrNttREYWdnZXLT0NCno6wg0rLWu9Ta0ru49k9iamVjdEdyYXBo1tDJ+tCnoaMgyPTKx9PQtuC49k9iamVjdEdyYXBoo6wg1PLT0LbguPbP4NOmtcRAU2luZ2xldG9uttTP86GjPC9zdHJvbmc+PC9lbT48YnIgLz48L3A+PHA+PGJyIC8+PC9wPjxwPjQu0dOz2deiyOsgPHN0cm9uZz5MYXp5IDwvc3Ryb25nPjoovLSjusDBvNPU2Cwgtci1vbX308O1xMqxuvKyxdeiyOspPC9wPjxwPjwvcD48cD5wdWJsaWMgY2xhc3MgPHN0cm9uZz5DbGFzc1Jvb208L3N0cm9uZz57PC9wPjxwPjxzdHJvbmc+CUBJbmplY3QgIExhenk8PC9zdHJvbmc+U3R1ZGVudD4gbGF6eVN0dWRlbnQ7IDwvcD48cD4JcHVibGljIHZvaWQgc3R1ZHkoKXs8L3A+PHA+CQk8c3Ryb25nPmxhenlTdHVkZW50LmdldCgpOy8v1eLR+b7NxNy1w7W90ru49lN0dWRlbnS21M/zPC9zdHJvbmc+PC9wPjxwPgl9PC9wPjxwPn0gPC9wPjxwPjxiciAvPjwvcD48cD41LszhuanV39eiyOsgPHN0cm9uZz5Qcm92aWRlcjwvc3Ryb25nPjwvcD4JPGVtPtPQ0KnH6b/2z8KjrCDE49Do0qq24Lj2ttTP88q1wP2jrCC2+LK7yse99r3216LI69K7uPa21M/zyrXA/aGj1eLKscTjv8nS1MD708NQcm92aWRlcjwvZW0+PHQ+PGVtPsq1z9ajrCDDv7TOtffTw1Byb3ZpZGVyPHQ+tcRnZXQoKbqvyv29q7e1u9jQwrXEPFQ+tcS21M/zyrXA/aGjPC90PjwvZW0+PC90PjxiciAvPjxwPnB1YmxpYyBjbGFzcyA8c3Ryb25nPkNsYXNzUm9vbTwvc3Ryb25nPns8L3A+PHA+PHN0cm9uZz4JQEluamVjdCAgUHJvdmlkZXI8PC9zdHJvbmc+U3R1ZGVudD4gcHJvdmlkZXJTdHVkZW50OyA8L3A+PHA+CXB1YmxpYyB2b2lkIHN0dWR5KCl7PC9wPjxwPgkJcHJvdmlkZXJTdHVkZW50LmdldCgpOwkvL7XDtb221M/zMTwvcD48cD4JCXByb3ZpZGVyU3R1ZGVudC5nZXQoKTsJLy+1w7W9ttTP8zI8L3A+PHA+CQkvL7bUz/MxILrNILbUz/MyIMrHwb249rK7zay1xLbUz/MuPC9wPjxwPgl9PC9wPjxwPn0gPC9wPjxiciAvPjxwPjYuz962qLf716K94iBAUXVhbGlmaWVyIKO6ILj2yMu+9bXD09C148/xIKGwV2Vi1tDX1Lao0uWx6sepobG1xLjQvvWjrNKy09C148/xIA=="C語言裡宏定義" 的樣子。

有些時候,單純類型(指這些基本的@Inject....等等)是不能夠滿足指定依賴的需求的。


在這種情況下,我們可以添加限定符注釋. 這種注釋本身有一個@Qualifier注釋。

下面是javax.inject中@Named的聲明代碼:

@Qualifier
@Retention(RUNTIME)
public @interface Named {
  String value() default "";
}

這樣寫完之後,我們就新擁有了一個注解@Named, 來幫助我們限定我們想提供的類對象,還有我們獲得的類對象的實例。

如:

public class ClassRoom{

@Inject @Named("胖虎") Student pangHu;


@Inject @Named("李四") Student liSi;

//這樣就限定了所要獲取的Student類對象實例的性質了

}


那麼我們之前說必須要有提供 類對象實例的方法,那麼現在有限定符的話,我們要怎麼來寫這樣的方法呢?


@Module

public class StudentModule{

@Provides @Named("胖虎") Student providePangHuStudent(){

return new Student("胖虎"); //假設該Student類有個這樣的構造函數

}

@Provides @Named("李四") Student provideLiSiStudent(){

return new Student("李四");

}

}

依賴關系也可以同時有多重限定符注釋。


7.靜態注入(staticInjections):建議謹慎使用這個特性, 因為靜態依賴注入很難測試和復用。

Dagger可以注入靜態變量。擁有@Inject靜態變量的類必須在@Module的staticInjections中明確說明。

@Module(
    staticInjections = LegacyCoffeeUtils.class
)
class LegacyModule {
}

可以使用ObjectGraph.injectStatics()注入靜態變量:

ObjectGraph objectGraph = ObjectGraph.create(new LegacyModule());
objectGraph.injectStatics();


8.編譯時有效性的檢查(這個很重要)

Dagger包含一個annotation 處理器, 這個處理器檢查module和注入的有效性。處理器非常嚴格, 若是有任何綁定是無效或者不完整的, 將引發編譯錯誤。


那麼應該遵循什麼樣的規則呢?我舉官網上的一個例子來跟大家分析下哈。


@Module
public class DripCoffeeModule {


@Provides

Heater provideHeater(Executor executor) {
return new CpuHeater(executor);
}


}

分析:由於我們知道,provideHeater是在有別的類@Inject了Heater類(或子類)的時候,會來調用這個方法,也就是說這個完全是由Dagger框架來調用的,而並非傳統意義上我們自己調用這個函數。


那麼問題應該就很明顯了吧???


這個參數,應該要由我們來提供吧?肯定有一個@Module裡面有一個方法是叫做 provideExecutor(), 但是我們這邊也不能用@Inject來注解這個參數。那要怎麼讓我們這個當前類,知道要去找那個方法拿這個參數呢?


有兩種方法:

1.把這個provideExecutor()方法放入到我們這個類中來,這樣子它就能夠找到這個方法並進行注入這個參數對象了。

2.在@Module中加入一個參數 complete=false, 標記說明該Module為不完整的Module。因為不完整的Module允許缺少對象實例

@Module(complete=false)
public class DripCoffeeModule {


@Provides

Heater provideHeater(Executor executor) {
return new CpuHeater(executor);
}


}


還有一個比較難理解的就是關於injects了

是這樣的,如果在@Module中加入參數injects (即所謂的:注入對象列表綁定)。

若是這個Module提供的對象綁定, 可能被injects列表中以外的類使用, 可以將改Module標記為library, 以避免出錯。

如:

@Module(

injects = ClassRoom.class,

library = true

)

public class StudentModule{

@Provides Student provideStudent(){

return new Student();

}


@Provides Others provideOthers(){

return new Others;

}

}

分析:由於ClassRoom中只用到了一個Student的類,而injects列表中也只寫了ClassRoom.class, 這樣的話,這個類提供的其他方法有可能被除了ClassRoom之外的類所用,那麼避免報錯就要在@Module加上參數library=true


9.所有@Provides要放在一個@Module中

由於Dagger規定所有@Provides要放在一個@Module中,所以我們要麼可以在一個Module中用includes參數把其他的Module類包含進來

或者比較建議的是:再創建一個空的Module類,把所有的Module都包含到這個Module中來。

@Module(
    includes = {
        StudentModule.class,
        ExecutorModule.class
    }
)
public class AppModules {
}

10.Module重載(引用官網的例子): 了解下就可以了

若對同一個依賴關系有多個@Provides函數, Dagger 將會報錯。但在有些情況下,是有必要替換production代碼的, 比如測試和開發。 在@Module中可以使用overrides =true , 重載其綁定關系。
下面這個JUnit測試利用Mockito, 重載了DripCoffeeModule的Heater綁定關系。這個Mock對象將inject到CoffeeMake中。

public class CoffeeMakerTest {
  @Inject CoffeeMaker coffeeMaker;
  @Inject Heater heater;

  @Before public void setUp() {
    ObjectGraph.create(new TestModule()).inject(this);
  }

  @Module(
      includes = DripCoffeeModule.class,
      injects = CoffeeMakerTest.class,
      overrides = true
  )
  static class TestModule {
    @Provides @Singleton Heater provideHeater() {
      return Mockito.mock(Heater.class);
    }
  }

  @Test public void testHeaterIsTurnedOnAndThenOff() {
    Mockito.when(heater.isHot()).thenReturn(true);
    coffeeMaker.brew();
    Mockito.verify(heater, Mockito.times(1)).on();
    Mockito.verify(heater, Mockito.times(1)).off();
  }
}

這種重載方式也很適合程序的小型變動, 例如付費版,免費版。



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved