編輯:關於android開發
什麼是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 belong
6 // in the individual module build.gradle files
7 }
然後是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 15
11 targetSdkVersion 23
12 versionCode 1
13 versionName "1.0"
14 }
15 buildTypes {
16 release {
17 minifyEnabled false
18 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 }
20 }
21
22 compileOptions {
23 sourceCompatibility JavaVersion.VERSION_1_8
24 }
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 @Inject
2 User user;
3
4 private void initData() {
5
6 user.setName("測試");
7 }
這時候我們允許程序發現空指針了;因為還缺少一個東西;
1 @Component
2 public interface ActivityComponent {
3
4 void inject(MainActivity MainActivity);
5 }
加上這個類之後 並且在Activity中對其初始化 完整代碼如下:
1 @Inject
2 User user;
3
4 private void initData() {
5 DaggerActivityComponent.builder().build().inject(this);
6 user.setName("測試");
7 }
這時候發現我們的user對象可以正常使用了;看上去感覺挺復雜的,但是對於大型項目引用的類過多的時候,Dagger的優勢就體現出來了;
接下來我一一解答你們的疑惑;
首先我們來了解這幾個基礎概念:
看了這些概念我們回到剛才的例子當中:
我們對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 @Singleton
2 @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 @Inject 2 OkHttpClient okHttpClient;
至此我們有兩種方式可以提供依賴,一個是注解了@Inject的構造方法,一個是在Module裡提供的依賴,那麼Dagger2是怎麼選擇依賴提供的呢,規則是這樣的:
步驟3:若不存在創建類方法,則查找Inject注解的構造函數,看構造函數是否存在參數
步驟3.1:若存在參數,則從步驟1開始依次初始化每個參數
這次依賴注入就先寫這麼多,Dagger結合MVP實現完美的配合,小伙伴們可以自己去研究一下其中的奧妙~
Android 貝塞爾曲線的淺析,android貝塞爾淺析
Android 貝塞爾曲線的淺析,android貝塞爾淺析博客也開了挺長時間了,一直都沒有來寫博客,主要原因是自己懶~~~此篇博客算是給2017年一個好的開始,同時也給2
簡單回調機制的基本建立,簡單回調機制建立
簡單回調機制的基本建立,簡單回調機制建立簡單回調機制的建立主要分為下面幾步: 1.寫一個回調類,寫出需要的構造方法 2.定義一個接口,裡面寫一個抽象方法,方法體(Stri
Kotlin中功能操作與集合(KAD 11),
Kotlin中功能操作與集合(KAD 11),作者:Antonio Leiva 時間:Feb 2, 2017 原文鏈接:https://antonioleiva.com/
Android數據存儲的三種方式介紹(SharedPrefrences,File,SQLite)
Android數據存儲的三種方式介紹(SharedPrefrences,File,SQLite) 1,使用SharedPrefrences 用於簡單少量的數據,數據的