依賴注入這個模式(模式已經用爛了,這裏再爛一次)是用來給應用的各部分解耦的。使應用開發更加可擴展,更容易維護。經過本文你會學到如何使用Dagger2來處理依賴。java
若是以對象須要另外的一個對象才能完成一個完整功能的話,那麼這裏就存在一個依賴。好比,悟空要用金箍棒才能三打白骨精,要筋斗雲才能十萬八千里。悟空有對金箍棒和筋斗雲的依賴。你能夠在悟空對象裏初始化金箍棒,也能夠用一個工廠方法批量生產金箍棒。使用依賴注入能夠無需一個專門的類來初始化這些依賴對象。這樣就實現瞭解耦。android
本教程會使用最新的Dagger2(當前的版本是2.2)。這裏是官網。你能夠在這裏找到最新的發佈。git
Android Studio是必須的。其餘:github
註解講解:後端
@Module
這個annotation修飾的類專門用來提供依賴@Provides
這個annotation修飾的方法用在Module
類裏@Inject
用來annotation一個依賴(能夠是構造方法、field或者通常的方法)@Component
鏈接@Module
和注入的橋樑這些名詞看起來很是抽象。下面稍微解釋一下。依賴反射並無什麼神奇的地方。只不過是咱們須要單獨寫初始化依賴的地方由其餘的框架代替了。這個依賴關係也有咱們常寫的代碼轉移到了「配置文件」中。api
在好久之前,依賴注入的框架就是這樣處理依賴注入的:讀取配置文件的依賴關係,而後用反射的方法初始化被依賴對象並賦值給調用依賴的對象。好比,咱們以前在悟空類中初始化金箍棒:android-studio
public class Wukong { private Jingubang jingubang; public Wukong(){ // 依賴 this.jingubang = Jingubang(); } }
後來有了使用配置文件的依賴注入(這裏都是虛構的文件格式):app
<xml> <com.xiyou.Wukong> <dependency field="jingubang"> <com.xiyou.Jingubang /> </dependency> </com.xiyou.Wukong> </xml>
在悟空使用金箍棒的時候,依賴注入框架自動初始化好了金箍棒,並賦值給了悟空。框架
如今使用Dagger2。這裏就有不得不說的牛X的地方了。由於是在Android裏能用的資源沒有後端那麼多。尤爲反射消耗比較大!因此Dagger爲了知足移動開發節約資源的須要,沒有使用反射實現依賴注入。而是在編譯的時候同時生成依賴注入的相關代碼。生成代碼的根據就是前文中說明的那些註解(annotation)以及使用這些annotation的類、接口。maven
總結起來就一句話,Dagger把你須要在悟空類裏寫的金箍棒類的初始化代碼都根據註解替你自動生成了!只不過這種生成的代碼比明晃晃的使用new
初始化的方法更加複雜一些。
把大象裝冰箱一共分幾步:
@Inject
註解修飾。XXXModule
。裏面寫的@Provides註解修飾的方法。這些@Provides方法返回「悟空類」和「金箍棒類」對象。好比@Provides Wukong provideWukong(){ return new Wukong(); }
@Component
註解修飾。通常叫作XXXComponent
。裏面寫一個注入方法:void inject(Wukong wk);
。這裏Wukong
只是一個例子。任何你準備要注入的類均可以代替上面參數的Wukong
類。@Inject
的field。最後,Dagger會根據上面的內容和最後的@Component
接口生成一個DaggerXXXComponent
的類型,使用這個類型來實現注入。上面的1到3步能夠理解爲依賴的配置。最後的XXXComponent
代替古老的Reflect方式實現注入。
第一步的@Inject修飾的構造函數和`@Module`的`provideXXX`方法兩者能夠省略一個。 Dagger能夠根據其中的任意一種配置建立依賴的對象。都寫上等於有了雙保險。
上文提到過屢次。Dagger 2厲害的地方就在於這個庫徹底不用反射,而是用在編譯期生成代碼的方式實現的依賴注入。這個特色致使在Android Studio配置的時候須要作一些額外的工做。
這裏假設你已經建立了一個新的Android應用項目。下面打開build.gradle
文件,咱們一步一步的來完成Dagger2的配置。
apply plugin: 'kotlin-android' // 非必須 apply plugin: 'kotlin-android-extensions' // 必須!!!
爲何要加一個新的plugin呢?這個是爲後面使用的kapt
和provided
提供支持的。gradle自己不支持這兩個操做。
buildscript { ext.kotlin_version = '1.0.1-2' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" } }
dependencies { // ...其餘略... compile 'com.google.dagger:dagger:2.2' kapt 'com.google.dagger:dagger-compiler:2.2' provided 'javax.annotation:jsr250-api:1.0' }
最後,同步Gradle。
下面就是Dagger一展身手的時候了。
悟空:
import javax.inject.Inject; /** * Created by uncle_charlie on 6/4/2016. */ public class Wukong { @Inject JinGuBang jinGuBang; @Inject public Wukong() { } public String useJinGuBang() { return this.jinGuBang.use(); } }
金箍棒:
import javax.inject.Inject; /** * Created by uncle_charlie on 6/4/2016. */ public class JinGuBang { @Inject public JinGuBang() { } public String use() { return "user Jing gu bang"; } }
@Inject
註解修飾。@Inject
註解。@Module
類建立@Module
註解的類,並在其中添加@Provides
註解修飾的方法。這些方法建立被依賴的對象。
import dagger.Module; import dagger.Provides; /** * Created by uncle_charlie on 6/4/2016. */ @Module public class XiYouModule { @Provides // @Singleton Wukong provideWukong() { return new Wukong(); } @Provides // @Singleton JinGuBang provideJinGuBang() { return new JinGuBang(); } }
@Singleton
註解代表,這個被依賴的對象在應用的生命週期裏只有一個實例。@Provides
方法和前一步說到的@Inject
註解的構造函數兩個能夠只寫一個。@Component
接口,鏈接@Module
和@Inject
@Module
和@Provides
方法提供了被依賴的對象。@Inject
在@Component
接口出現的地方則是指明瞭須要注入的地方(通常是一個field)。@Component
接口就是用來把他們鏈接起來的。
import android.app.Activity; import javax.inject.Singleton; import dagger.Component; /** * Created by uncle_charlie on 6/4/2016. */ @Component(modules = {XiYouModule.class}) @Singleton public interface XiYouComponent { void inject(Wukong wk); void inject(Activity a); }
其中inject()
方法裏使用的對象,就是包含@Inject
的field的須要注入的對象。
在這個接口中也能夠不用inject()
方法,而使用provideXXX()
方法後面會有更多介紹。
注意:@Component接口必定要在直接中指明@Module類型
@Component
接口獲取對象通過前面的步驟,依賴和被依賴對象關係都已經配置好了。下面就來獲取被依賴對象來注入依賴對象。
public class MainActivity extends AppCompatActivity { private static final String TAG = "##MainActivity"; @Inject Wukong wukong; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView welcomeTextView = (TextView) findViewById(R.id.welcome_textview); // 1 XiYouComponent xiYouComponent = DaggerXiYouComponent .builder() // 2 .xiYouModule(new XiYouModule()) .build(); xiYouComponent.inject(this); // 3 welcomeTextView.setText(wukong.useJinGuBang()); } }
首先主要到屬性@Inject Wukong wukong;
已經在MainActivity
聲明瞭。這裏代表一個依賴關係:這個activity依賴於悟空,並準備注入悟空對象。
DaggerXiYouComponent
就是Dagger根據咱們的XiYouModule
類生成的代碼。DaggerXiYouComponent
的builder
添加XiYouModule
的實例。若是這個Module只須要用到無參構造函數的話能夠用一種省略用法:create()
方法。能夠簡寫爲:DaggerXiYouComponent .builder() // 2 //.xiYouModule(new XiYouModule()) //.build() .create();
inject(this)
方法以後注入即完成。因此能夠直接使用@Inject Wukong wukong;
屬性來調用方法:welcomeTextView.setText(wukong.useJinGuBang());
最後在activity中顯示方法返回的文字。運行代碼,看看結果吧。
以上內容能夠歸納爲:什麼被依賴,就把什麼放在@Module
類裏(或者什麼被依賴,就給什麼添加@Inject
的無參構造函數)。什麼有依賴(@Inject
屬性),就把什麼放在@Component
接口的inject()
方法參數裏。(或者有什麼@Inject
屬性,就在@Component
接口裏provide什麼對象)。這個歸納不必定嚴密,可是基本用法所有包括了。
依賴注入是頗有用的。以上的內容只是Dagger2依賴注入的一部分。各位讀者還須要根據官方文檔多加練習才能更好的理解依賴注入和Dagger的各類用法。