MVP + RxJava + Retrofit + Dagger2 現在已經成了Android開發的主流框架,爲了避免落伍,我也開始了這個組合框架的學習,力求擺脫以前的那種簡單粗暴的分包模式。因而也開始了 Dagger2 的學習之路。這幾天斷斷續續的也看了不少文章,其中固然有不少優秀的文章,可是慢慢的以爲並無哪一篇文章,是徹底的能讓人只須要看一篇就能徹底讓一我的從0開始入門的,Dagger2這個框架學習起來仍是比較費勁的,每每是搜了不少文章,綜合起來才慢慢的能把不少東西搞懂,這就使得不少人還沒入門就屢次放棄了(說實話,我也放棄了不少次)。在這裏,我想力求作到從一個「白癡」的角度(我是不會認可是個人)進行講解,以問題爲導向來說解,不少時候咱們以爲寫博客的人雖然寫了不少,以爲很牛逼,但可恨的是,咱們仍是不懂。其實這並非咱們的錯,只是做者忘記了當初本身是怎麼過來的,各類問題是怎麼一步步被提出來的,結果就是變成了教科書式的講解。下面就讓咱們一切從頭來過,這一次,決不放棄。html
這裏,我就不在粘貼那些很官方的描述了,直接大白話。「依賴注入」,從這個詞來講,就是 「依賴」 和 「注入」 兩個部分嘛。所謂「依賴」,和咱們生活中理解的同樣,好比說汽車和汽油的關係,汽車只有在有汽油存在的狀況下才有意義,嚴重依賴汽油。而「注入」,很容易讓咱們想到注射器,將一種液體注入到另外一種容器中,這裏的「注入」也是同樣的,只不過是講對象綁定到另外一個類中而已(簡單點來說就是經過引用進行賦值)。java
那爲何須要依賴注入呢?其實就是爲了簡化無用操做,提升效率,而且對代碼進行解耦,使得需求或者一個地方的代碼變更,儘量小的引發其餘部分代碼的修改。咱們以箱子和箱子的水果這個場景爲例,進行講解。android
首先建立一個Box類,在其中又依賴了兩個類:Apple 和 Banana。編程
public class Box { Apple mApple; public Box(Apple apple){ mApple = apple; } }
箱子裏裝有蘋果。下面看具體使用:設計模式
public class MainActivity extends AppCompatActivity { Apple mApple; Box mBox; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mApple = new Apple(); // 先建立 Apple 對象 mBox = new Box(mApple, mBanana); // 將建立好了的 Apple 對象傳入 Box 對象的構造函數中 }
能夠看到,咱們要向獲得一個Box對象,必需要先手動生成一個Apple對象和一個Banana對象,試想一下,若是在之後,咱們修改了Apple類,在其中添加了對蘋果的描述,改變了構造方法,好比變爲:app
public class Apple { public Apple(String desctiption){ Log.i("qc","蘋果的描述爲: "); } }
那咱們就須要再去修改 MainActivity.java 類,顯然按,這種編程習慣是很差的。咱們能不能經過其餘方法,來下降這種影響呢?其實,在編程中咱們不少時候是用到過的,只是咱們沒意識到,想一想,在列表加載中,爲適配器設置數據、爲列表項加載頭佈局和尾佈局的時候你是怎麼設置的?Bingo,經過setXXX(...)方法,好比,在Adapter中設置一個public方法來設置數據集:框架
public void setData(List data){ ... }
代碼編寫的多了,就會更加的接近設計模式、編程思想的本質,畢竟設計模式源於實踐而且指導實踐的,咱們可能不再願意去直接在建立Adapter的構造函數中直接傳入數據集了。
若是以爲這點我說的不太清楚的話,能夠參考這篇文章:使用Dagger2前你必須瞭解的一些設計原則
其實,Dagger2 的思想,跟這個就很像,都是爲了解耦。使用 Dagger2 ,這些setXXX(...)的方法,徹底就不須要咱們本身去作了。ide
這裏再補充一點,若是你熟悉MVP的話,就很容易能感覺到 Dagger2 的魅力,MVP 模式中,View和 Presenter 互相持有對方的引用,而 Presenter 同時又持有 Model 的引用,這樣,就形成了View和 Presenter 之間的耦合性比較大,使用 Dagger2 能夠減弱這種耦合,直接將 Presenter 經過依賴注入的方式注入到 View 中(例如Activity),固然,若是你還不瞭解MVP的話,如今學習這篇文章,千萬別再跑去看MVP,而丟了主次,徹底不須要,那只是 Dagger2 的一個使用場景。函數
在學習Dagger2以前,你必定要了解的東西就是Java中的註解,能夠說若是不懂註解的話,學習Dagger2 是很是痛苦的一件事,甚至徹底不知道整個過程是怎麼進行的。關於註解,並不難,一兩篇文章就能夠搞懂,不會花費你不少時間的,能夠參考這篇文章:JAVA 註解的幾大做用及使用方法詳解佈局
之前咱們每每是在須要的地方手動的去經過 new 來生成對象,對象的生成和對象的使用是在同一個地方,而 Dagger2 將對象的是生成和其使用分開。說白了,Dagger2 的整個過程就兩個:
建立並初始化對象(被依賴的對象,好比 Apple)
將初始化好的對象經過「中間人」放到須要它的那個對象中(目標類,或者成爲容器,好比 Box)
那麼就讓咱們直接經過具體的例子來進行講解,讓你們更直觀的感覺到整個過程。
如今Dagger2拋棄了以前採用的apt自動生成代碼的方式,而採用annotationProcessor,於是
若是你使用的Gradle插件版本在2.2及以上,只須要在應用對應的build.gradle文件中添加如下依賴便可:
dependencies { ... ... // Dagger2相關依賴 compile 'com.google.dagger:dagger:2.11-rc2' annotationProcessor 'com.google.dagger:dagger-compiler:2.11-rc2' }
若是用的是比較舊的版本,能夠參考GitHub上項目幫助文檔:https://bitbucket.org/hvisser...
既然是依賴注入,咱們首先須要作的就是把對象生產出來。那怎麼生成一個對象呢,很容易想到在構造函數前加一個 new ,如:new Apple(),可是既然 Dagger2 能讓它自動生成,咱們固然不須要本身動手,只須要作某種標記,好比能夠直接加上@Inject註解。
這裏咱們首先提出來,生成所需對象的方式有兩種:
@Inject 註解提供方式:在所需類的構造函數中直接加上 @Inject 註解
@Module 註解提供方式:經過新建一個專門的提供這類來提供類實例,而後在類名上面添加 @Module 註解,在類中本身定義方法,手動經過 new 來進行建立,這種主要是針對第三方庫中,咱們沒法直接在構造函數中添加 @Inject 註解的狀況。
這裏,咱們先針對第一種狀況進行講解,也就是 @Inject 註解,先跑通整個流程
下面一步步講解:
第一步,很簡單:就是在Apple類的構造函數上添加 @Inject 註解標記
public class Apple { @Inject // 注意此處的標記是加在構造函數上面的,這個是無參構造函數,有參構造函數的狀況下以後會講 public Apple(){ } public String getDescription(){ return "這個蘋果然好吃"; } }
這樣,咱們就完成了提供者端的操做了,很簡單吧,僅僅只是在構造函數上面添加了一個 @Inject 註解。
這一步,是告訴編譯器及其餘處理程序,咱們須要經過此處來生成對象,從而供之後進行依賴注入。
第二步,在目標類中的對應成員變量上也添加相同的註解 @Inject (注意,在目標類中這個註解始終是 @Inject ,而不會由於以後使用 @Module 這種方式而改變)
public class MainActivity extends AppCompatActivity { @Inject Apple mApple; // 在這裏,咱們添加了@Inject 註解,告訴處理程序,咱們須要將對象注入到此處,給此引用賦值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
在這一步,咱們經過在目標類中屬性上添加 @Inject 註解,來告訴編譯器和其餘代碼自動生成程序,咱們須要將以前生成的對象注入到這裏(賦值給這裏的引用)。
注意,屬性的訪問修飾符必定不能是private類型的,不然沒法經過Dagger2進行依賴注入,由於咱們實際上是經過傳入引用,而後經過引用來調用其中的屬性,一旦聲明爲private,咱們天然沒法經過mainActivity.mApple
這種方式來進行賦值操做了。
至此,咱們就完成了最基本的兩步了,咱們知道了從哪裏生成對象,也知道了生成以後的對象須要在哪裏使用,可是,如何將兩者聯繫起來呢,也就是說,我如何經過某種方式,將生成的對象送達到須要的地方呢?這就須要一個「中間人」來起到橋樑的做用,讓兩者產生實質上的關聯。這就是接下來要講到的 @Component 註解了。
第三步,經過 @Component 進行牽線搭橋
咱們最好創建一個包,名叫component,以方便管理。在該包下新建一個接口類,建議統一以Component做爲後綴,好比下面的 MainComponent.java 。
@Component public interface MainComponent { void inject(MainActivity activity); }
咱們在該接口上面添加了 @Component 註解,同時定義了一個抽象方法:void inject(MainActivity activity);
注意,這個方法,返回值是void
類型的,後面的方法名能夠隨便起,括號內的參數是咱們須要將對象注入的類,必定要是具體的類,而不能是其父類。其實,以後咱們使用的時候,就是將對應的Activity
傳進去,而後經過引用調用該對象的屬性進行賦值,思想很簡單。這裏要強調一點,這裏並非必定要求是void
類型的,能夠有具體的返回值,這種狀況咱們會在以後具體討論,這裏先經過這個void
簡單類型來學習,避免複雜化。函數名也通常先命名爲inject
,便於理解。
其實,寫到這裏,咱們的整個過程基本上就完成了,下面只須要經過代碼,進行實際的注入就行了。可能你會問,這就完成了?咱們上面只是定義了一個接口,並無具體的實現啊,怎麼就能注入呢?接下來,咱們就來見證奇蹟的時刻把,咱們把項目編譯一下,或者直接點擊AS上的綠色的錘子圖標:
而後你打開下圖的目錄,就會發現會自動生成一些類。
這就是咱們在build.gradley依賴中添加的註解處理器(AnnotationProcess)給咱們自動生成的。以前是沒有apt這整個目錄的,這裏面咱們能夠看到,它也按照咱們分的包的結構來生成的,好比「component」包。這裏面如今對咱們來說最重要的也是直接跟咱們發生關係的就是DaggerMainComponent.java
這個類,咱們進行具體的依賴注入其實就是使用的這個類,這個類是Dagger2框架自動爲咱們生成的,能夠看到,它是以Dagger開頭的。當咱們建立了一個Component,好比MainComponent以後,系統會自動爲咱們生成一個以Dagger爲前綴,後面跟上咱們的Component名的一個具體實現類。先知足一下你的好奇心,咱們點進去,看一下這個類。
public final class DaggerMainComponent implements MainComponent { private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerMainComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static MainComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Apple_Factory.create()); } // 看到了吧,這個就是咱們在以前定義的接口,此處系統自動爲咱們進行了實現 @Override public void inject(MainActivity activity) { mainActivityMembersInjector.injectMembers(activity); } public static final class Builder { private Builder() {} public MainComponent build() { return new DaggerMainComponent(this); } } }
能夠看到,它實現了咱們以前寫的MainComponent接口,裏面也對咱們以前定義的抽象方法進行了實現。
@Override public void inject(MainActivity activity) { mainActivityMembersInjector.injectMembers(activity); }
到這裏知道爲啥我說名字能夠隨便命名了吧。
好啦,看到這裏就夠了,千萬別陷進去,一下子咱們還會回來繼續分析這個類的,千萬別以爲我是在淺嘗輒止啊。
仍是再提醒一下,編寫完以後,必定要編譯一下項目,不然這些不會生成的,下面你也無法用Dagger***Component
來進行注入了,會提醒你找不到該類。
第四步,也是最後一步,使用Dagger***Component
進行依賴注入
咱們只須要在咱們的目標類中,調用注入代碼就能夠了,以下代碼:
public class MainActivity extends AppCompatActivity { @Inject Apple mApple; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 將依賴注入到該Activity中 DaggerMainComponent .builder() .build() .inject(this); // 打印測試消息 Timber.i(mApple.getDescription()); } }
運行項目,能夠看到,在日誌中已經打印出來了咱們Apple
類中的信息(這裏使用的是JakeWharton
大神的日誌打印框架,你直接用 Log.i 打印就好)。
好了,到這裏,咱們算是將Dagger2 的一個流程整個跑完了,但這只是一種注入的方式,也就是直接經過在類的構造函數上面添加@Inject註解來完成依賴注入,在下一篇文章中我將會爲你們講解兩一種提供對象的方式:@Module