編輯:關於Android編程
Dagger 是一種android平台的依賴注入框架,是有一家專注於移動支付的公司,Square公司推出的庫,這家公司也推出了
其他在Android開發中常用庫:otto,okhttp,retrofit等等,這些在接下的博文中會一一介紹。
對Dagge的介紹,除了官方文檔的介紹外,接下來的這些分析,本人覺得是比較不錯的,也許在不熟悉Dagger的情況下看這
寫內容,你會覺得無厘頭,不知道講什麼。根據本人經驗,建議先了解Dagger的使用再來看這個會對了解Dagger有比較好的效果。
接下來就進入正題,進行實例講解,與官方例子一樣,我這裡也用煮咖啡的例子來說明,只不過官方的例子是用在Java上,這裡
的例子使用Android開發來進行,並且對其也進行了改進。
首先我先說明一下這個過程,既然是煮咖啡,就要由一個加熱器(Heater),加熱之後要有一個倒(Pump)的過程,倒好之後才能供給人
們喝(Drink)。就這麼一個簡單的邏輯,你也許會和我開始一樣,覺得這有什麼難的,很少的代碼就能搞定。是的,我們就要用這麼一
個簡單的事件,來看看用Dagger是怎麼實現的。
首先,我們來設計Heater、Pump、Drink這三個接口,如下:
package com.example.app.dagger; /** * Created by zjb on 14-1-22. */ interface Heater { void on(); //加熱器打開 void off();//加熱器關閉 boolean isHot();//加熱是否完畢 }
package com.example.app.dagger; /** * Created by zjb on 14-1-22. */ interface Pump { void pump(); //倒咖啡 boolean isPumped();//是否倒好 }
package com.example.app.dagger; /** * Created by zjb on 14-1-22. */ interface Drink { void drink(); //喝咖啡 }Ok,接口已經設計完畢,是否合理暫且不細究,接下來我們分別實現這三個接口(有用到AndroidAnnotations框架(請看上篇博文)):
package com.example.app.dagger; import android.content.Context; import android.widget.Toast; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; import org.androidannotations.annotations.UiThread; /** * Created by zjb on 14-1-22. */ @EBean class ElectricHeater implements Heater { boolean heating = false; @RootContext Context context; @Override public void on() { heating = true; System.out.println(-----Heating-----); reportHeating(); } @UiThread void reportHeating(){ Toast.makeText(context,Electric heater heating.....,Toast.LENGTH_LONG).show(); } @Override public void off() { heating = false; } @Override public boolean isHot() { return heating; } }
使用@EBean注解會在編譯過程中產生一個ElectricHeater子類ElectricHeater_.class, 接下來會用到。
Pump接口實現:
package com.example.app.dagger; import javax.inject.Inject; /** * Created by zjb on 14-1-22. */ class Thermosiphon implements Pump { private final Heater heater; boolean pumped = false; @Inject Thermosiphon(Heater heater) { this.heater = heater; } @Override public void pump() { if (heater.isHot()) { System.out.println(-----Pumping-----); pumped = true; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public boolean isPumped() { return pumped; } }
package com.example.app.dagger; import javax.inject.Inject; /** * Created by zjb on 14-1-22. */ class PeopleDrink implements Drink { private Pump pump; @Inject PeopleDrink(Pump pump) { this.pump = pump; } @Override public void drink(){ if(pump.isPumped()){ System.out.println(-----Drinking-----); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }三個接口已經實現完畢,對比三個實現類,有沒有發現什麼共同點. 是的,你會發現,三個類中都有使用@Inject來注解
他們的構造函數,這是因為Dagger要用@Inject來注解一個類的實例構造函數,當請求一個新實例的時侯,Dagger就會獲取這個
參數值並調用這個構造函數。也許你不明白,沒關系,繼續往下看,會給出詳細解釋。
Dagger不僅能向上述代碼那樣注解構造函數,也能直接注解fields(Dagger can inject fields directly),看這個類:
package com.example.app.dagger; import javax.inject.Inject; import dagger.Lazy; /** * Created by zjb on 14-1-22. */ class CoffeeMaker { @Inject Lazy將Heater、Pump及Drink注入到類CoffeeMaker中,就可以直接使用並調用其方法。值得注意的是,在注解的時候Daggerheater; @Inject Pump pump; @Inject Drink drink; public void brew() { heater.get().on(); pump.pump(); System.out.println(-----Pumped-----); heater.get().off(); drink.drink(); } }
就會通過@Module中的@Provides方法調用構造函數來獲得實例對象(下面馬上介紹)。如果你@Inject fields卻沒有@Inject
構造函數,Dagger就會使用一個存在的無參構造函數,若沒有@Inject構造函數,就會出錯。繼續看@Module
package com.example.app.dagger; import android.content.Context; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * Created by zjb on 14-1-22. */ @Module(injects={CoffeeActivity_.class},library = true,complete = false) /*@Module(injects = {CoffeeActivity_.class},includes = {PumpModule.class,DrinkModule.class},library = true,complete = false)*/ class DripCoffeeModule { private final Context context; public DripCoffeeModule(Context context) { this.context = context.getApplicationContext(); } @Provides @Singleton Context appliactionContext() { return context; } @Provides @Singleton Heater provideHeater(){ return ElectricHeater_.getInstance_(appliactionContext()); } @Provides @Singleton Drink provideDrink(PeopleDrink drink){ return drink; } @Provides @Singleton Pump providePump(Thermosiphon pump){ return pump; } }
解釋一下前面一句話:如果說@Inject實現了注入,那麼@Provides就是實現依賴關系。@Provides方法方法的返回類型就定義了它
所滿足的依賴。你也許注意到了我注釋掉的@Module,這是什麼意思呢?是這樣的,假如我這裡將providesDrink方法刪除,我可以
另建一個DrinkModule.java文件,由於所有的@Provides必須屬於一個Module,所以必須將DrinkModule類includes進來:
package com.example.app.dagger; import dagger.Module; /** * Created by zjb on 14-1-22. */ @Module(library = true,complete = false) public class DrinkModule { @Provides @Singleton Drink provideDrink(PeopleDrink drink){ return drink; } }(@Module後的library和complete是什麼意思這裡先不說)
至此,Dagger中的三個重要annotation已經全部涉及到了,那麼它是如何管理這些依賴關系的呢?繼續往下看:
package com.example.app.dagger; import android.app.Application; import org.androidannotations.annotations.EApplication; import dagger.ObjectGraph; /** * Created by zjb on 14-1-22. */ @EApplication public class CoffeeApplication extends Application { private ObjectGraph objectGraph; @Override public void onCreate() { super.onCreate(); objectGraph = ObjectGraph.create(new DripCoffeeModule(this)); } public ObjectGraph getObjectGraph() { return objectGraph; } }上邊提到,Dagger是通過什麼管理或者組織依賴關系的呢,就是通過ObjectGraph(對象圖表)。
最後的主程序:在節面中就一個按鈕來觸發整個過程
package com.example.app.dagger; import android.app.Activity; import android.widget.Toast; import com.example.app.R; import org.androidannotations.annotations.AfterInject; import org.androidannotations.annotations.App; import org.androidannotations.annotations.Background; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.UiThread; import javax.inject.Inject; import dagger.ObjectGraph; /** * Created by zjb on 14-1-22. */ @EActivity(R.layout.coffee) public class CoffeeActivity extends Activity { @App CoffeeApplication coffeeApplication; @Inject CoffeeMaker maker; @AfterInject void daggerInject(){ ObjectGraph objectGraph = coffeeApplication.getObjectGraph(); objectGraph.inject(this); } @Click(R.id.coffeeClick) @Background void coffeeClicked(){ maker.brew(); coffeeBrew(); } @UiThread void coffeeBrew(){ Toast.makeText(this,Coffee has been pumped...,Toast.LENGTH_LONG).show(); } }
程序運行的結果:
com.example.app I/System.out﹕ -----Heating----- com.example.app I/System.out﹕ -----Pumping----- com.example.app I/System.out﹕ -----Pumped----- com.example.app I/System.out﹕ -----Drinking-----
使用Dagger,我們能夠很好的實現依賴關系,也能更清楚的看到我們的代碼在做些事情,能夠清晰地顯示出各部分的
邏輯關系,通過下面這張圖,我們能夠很清楚的看到它的每一步操作:
好了,Dagger呢就介紹到這裡,源碼這次就先不上傳了,等到介紹完Otto之後,我會抽空上傳到資源,供大家下載學習。
內容細節說的不全請見諒、指教。如果你對使用dagger有興趣也歡迎一起討論、學習。這是春節前最後一篇文章了,祝大家
搶到一張好票,馬上有錢、有對象!
注:文章原創 轉載請注明出處:CSDN 菜鳥的成長史
附:
Jake Warhton的Dagger ppt 下載資源
如上一篇博客《Android動畫之一:Drawable Animation》所說,android動畫主要分為三大部分,上一篇博客已經講解Drawable Animatio
謹記(指定選擇器Intent.createChooser())開始今天的內容前,先閒聊一下:(1)突然有一天頭腦風暴,對很多問題有了新的看法和見解,迫不及待的想要分享給大
Android開發記錄16-友盟第三方登錄、分享實現 本篇博客給大家分享一個筆者正在做的關於第三方登錄、分享的實例,這裡選用的是友盟社會化組件。 博客大綱如
新浪微博是全中國最主流,最具人氣,當前最火爆的微博產品。用一句話隨意記錄生活,用手機隨時隨地發微博。微博同樣也可以和朋友聊私信,你可以關注你想關注的人,了解