編輯:關於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、Service的種類按運行地點分類: 類別 區別 優點 缺點 應用
有很多地方要用到DatePickerDialog。但有時項目用到的主題樣式是很丑的樣式,顯示出來的真丑。而我們真正想要的樣式是這樣的。這個就漂亮多了。而且很多的時候都不需
public class MainFragmentPagerAdapter extends FragmentPagerAdapter implement
最近學習了一個視頻公開課,講到了利用HorizontalScrollView仿ViewPager設計的一個簡單相冊,其實主要用了ViewPager緩存的思想。此篇文章參考