淺析Dagger2的使用,淺析Dagger2使用
什麼是Dagger2
Dagger是為Android和Java平台提供的一個完全靜態,在編譯時間進行依賴注入的架構,原來是由Square公司維護,現在由Google維護。
我們知道Dagger是一個依賴注入的架構,那麼什麼是依賴注入呢?
我們在activity中有可能會用到很多很多的類,這些類要在activity中進行執行個體化,這樣就導致我們的activity非常依賴這麼多的類,這樣的程式耦合非常
嚴重,不便於維護和擴充,有什麼辦法可以不去依賴這些類呢,這時候就需要有一個容器(IoC),將這些類放到這個容器裡並執行個體化,我們activity在用
到的時候去容器裡面取就可以了,我們從依賴類到依賴這個容器,實現瞭解耦,這就是我所理解的依賴注入,即所謂控制反轉;
簡單的說 Dagger就是用來創造這個容器,所有需要被依賴的對象在Dagger的容器中執行個體化,並通過Dagger注入到合適的地方,實現解耦,MVP架構就是為解耦而生,因此MVP和Dagger是絕配;
舉個栗子?
通常情況下我們引用一個類的做法:
我們先定義一個簡單的類:
1 public class User { 2 private String name; 3 4 public String getName() { 5 return name; 6 } 7 8 public void setName(String name) { 9 this.name = name;10 }11 }
在Activity中對其操作
1 private void initData() {2 3 User user = new User();4 5 user.setName("測試");6 }
以上是最普通的用法
接下來我們來看Dagger2的用法
我們先來配置一下Dagger2
首先在項目的 build.gradle:
1 dependencies {2 classpath 'com.android.tools.build:gradle:1.5.0'3 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'4 classpath 'me.tatarka:gradle-retrolambda:3.2.0'5 // NOTE: Do not place your application dependencies here; they belong6 // in the individual module build.gradle files7 }
然後是APP的 build.gradle
1 apply plugin: 'com.android.application' 2 apply plugin: 'com.neenbedankt.android-apt' 3 apply plugin: 'me.tatarka.retrolambda' 4 android { 5 compileSdkVersion 23 6 buildToolsVersion "23.0.1" 7 8 defaultConfig { 9 applicationId "jiao.com.jiaoproject"10 minSdkVersion 1511 targetSdkVersion 2312 versionCode 113 versionName "1.0"14 }15 buildTypes {16 release {17 minifyEnabled false18 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'19 }20 }21 22 compileOptions {23 sourceCompatibility JavaVersion.VERSION_1_824 }25 26 }27 28 dependencies {29 compile fileTree(dir: 'libs', include: ['*.jar'])30 testCompile 'junit:junit:4.12'31 compile 'com.android.support:appcompat-v7:23.3.0'32 compile 'com.android.support:design:23.3.0'33 apt 'com.google.dagger:dagger-compiler:2.2'34 provided 'org.glassfish:javax.annotation:10.0-b28'35 compile 'com.google.dagger:dagger:2.2'36 compile 'com.jakewharton:butterknife:7.0.1'37 compile 'com.squareup.okhttp3:logging-interceptor:3.3.0'38 }
首先
1 public class User { 2 private String name; 3 4 @Inject 5 public User() { 6 } 7 8 public String getName() { 9 return name;10 }11 12 public void setName(String name) {13 this.name = name;14 }15 }
發現有什麼變化了沒?@Inject是什麼東東?待會我們來說;
接著我們看怎麼使用
1 @Inject2 User user;3 4 private void initData() {5 6 user.setName("測試");7 }
這時候我們允許程式發現null 指標了;因為還缺少一個東西;
1 @Component2 public interface ActivityComponent {3 4 void inject(MainActivity MainActivity);5 }
加上這個類之後 並且在Activity中對其初始化 完整代碼如下:
1 @Inject2 User user;3 4 private void initData() {5 DaggerActivityComponent.builder().build().inject(this);6 user.setName("測試");7 }
這時候發現我們的user對象可以正常使用了;看上去感覺挺複雜的,但是對於大型項目引用的類過多的時候,Dagger的優勢就體現出來了;
接下來我一一解答你們的疑惑;
首先我們來瞭解這幾個基礎概念:
- @Inject Inject主要有兩個作用,一個是使用在建構函式上,通過標記建構函式讓Dagger2來使用(Dagger2通過Inject標記可以在需要這個類實 例的時候來找到這個建構函式並把相關執行個體new出來)從而提供依賴,另一個作用就是標記在需要依賴的變數讓Dagger2為其提供依賴。
- @Provide 用Provide來標註一個方法,該方法可以在需要提供依賴時被調用,從而把預先提供好的對象當做依賴給標註了@Injection的變數賦值。provide主要用於標註Module裡的方法
- @Module 用Module標註的類是專門用來提供依賴的。有的人可能有些疑惑,看了上面的@Inject,需要在建構函式上標記才能提供依賴,那麼如果我們需要提供 的類建構函式無法修改怎麼辦,比如一些jar包裡的類,我們無法修改源碼。這時候就需要使用Module了。Module可以給不能修改源碼的類提供依 賴,當然,能用Inject標註的通過Module也可以提供依賴
- @Component Component一般用來標註介面,被標註了Component的介面在編譯時間會產生相應的類的執行個體來作為提供依賴方和需要依賴方之間的橋樑,把相關依賴注入到其中。
看了這些概念我們回到剛才的例子當中:
我們對User的建構函式進行了 @Inject的標註 意思就是告訴Dagger2 如果有誰要使用User這個類,我標註的這個建構函式,你可以直接用來執行個體化該類;
然後我們在Activity中對User也進行了@Inject的標註 意思是告訴Dagger2 這個類需要被注入,簡單的說就是 這個類我要用,你幫我執行個體化;
細心的讀者可能會發現 這樣會不會太簡單了,是的 是太簡單了不太正常,哈哈,上面的例子中還有一個標註@Component 光靠@Inject的標註是不足以完成注入的 我們需要用@Component來完成注入;
上例中被@Component標記的ActivityComponent介面就是一個注入器; void inject(MainActivity MainActivity);的意思是MainActivity中要用到這個注入器然後我們在MainActivity中對注入器進行初始化 DaggerActivityComponent.builder().build().inject(this); 然後Activity中所有被@Inject標記的類,都會通過ActivityComponent來進行初始化;
我們再把上例中的注入過程梳理一下:
1、首先定義一個類User 並在其建構函式用@Inject標註,表示告訴Dagger2這是我的建構函式,如果有地方要用到我,就用該建構函式對我執行個體化;
2、建立一個@Component標註的注入器介面,並在注入器中使用 void inject(MainActivity MainActivity);來表明哪裡要用到注入器;
這裡表示MainActivity中要用到該注入器
3、在MainActivity中對注入器進行初始化DaggerActivityComponent.builder().build().inject(this); 初始化後該注入器就可以正常使用了;
4、在MainActivity中對需要注入的類 User用@Inject進行標註,表示該類需要被注入,即執行個體化;
注意:在代碼編寫過程中 我們會發現DaggerActivityComponent會不存在,這是因為注入器是在編譯的過程中才產生,所以我們在對注入器編寫完成後
Make Project 一下就會產生DaggerActivityComponent
————————————————————————————————————————————————————————————————————————————————
現在我們已經明白了@InJect @Component的作用了,接下來我們來研究@Module和@Provide
通過上面的例子我們發現 @Inject是對類的建構函式進行標註來進行執行個體化的,但是有些類,比如第三方OkHttpClient,我們是無法對其源碼進行修改的
即對其建構函式進行標註,這個時候我們就用到了@Module
@Module是什麼意思呢 @Module是和@Component配合使用的 意思就是告訴注入器,如果你在執行個體化對象的時候,沒有找到合適的建構函式,你就來我這裡找,@Module通常標註一個類,該類裡面可以執行個體化各種類,Component在注入對象的時候先去Module中找,如果找不到就會檢查所有被@Inject標註的建構函式;所以我們可以把OkHttpClient放到Module中;
1 @Module 2 public class ActivityMoudle { 3 4 @Provides 5 @Singleton 6 OkHttpClient provideOkHttpClient() { 7 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); 8 loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 9 10 Interceptor apikey = chain -> chain.proceed(chain.request().newBuilder()11 .addHeader("apikey", Constants.Api_Key).build());12 13 OkHttpClient okHttpClient = new OkHttpClient.Builder()14 .readTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)15 .connectTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)16 .addInterceptor(apikey)17 .addInterceptor(loggingInterceptor)18 .build();19 20 return okHttpClient;21 }22 23 }
以上代碼我們不需要知道是幹嘛的,我們只知道該類中的方法返回一個okHttpClient的執行個體;
一個被@Module標註的類用來返回一個okHttpClient的執行個體;
我們再來看一下在Component中的代碼:
1 @Singleton2 @Component(modules = ActivityMoudle.class)3 public interface ActivityComponent {4 5 void inject(MainActivity MainActivity);6 }
可以看到標註頭多了@Component(modules = ActivityMoudle.class),表示告訴注入器如果你要注入的類沒有找到建構函式,你就去ActivityMoudle.class中找
@Provide 用來標註一個方法,告訴注入器,我標註的方法你可以用來提供執行個體;
@Singleton 顧名思義,標註該執行個體化的對象為單例
然後我們在Activity直接標註使用就可以了
1 @Inject2 OkHttpClient okHttpClient;
至此我們有兩種方式可以提供依賴,一個是註解了@Inject的構造方法,一個是在Module裡提供的依賴,那麼Dagger2是怎麼選擇依賴提供的呢,規則是這樣的:
這次依賴注入就先寫這麼多,Dagger結合MVP實現完美的配合,小夥伴們可以自己去研究一下其中的奧妙~