上一節我們介紹了《Dagger2教程一之配置(原)》,這一節我們來介紹Dagger2的具體使用方法。
一、原始方式
我們先來看一下如果不使用Dagger的情況,我們在Activity中創建一個Bean的對象,其構造方法無需傳遞任何參數,但是內部會初始化其成員name,然後在Activity中使用該對象。
Bean的內容爲: public class Bean {
private String mName = null;
public Bean() {
this.mName = "原始方式";
}
public String getName() {
return mName;
}
}
在Activity中創建並使用該對象: private void testOrignal() {
Bean bean = new Bean();
Log.d(TAG, "不使用Dagger時 Name:" + bean.getName());
}
其結果如下圖所示:二、最簡單的Dagger使用方式
接下來我們通過一個例子來介紹如何通過Dagger來實現上面的代碼。
2.1、改造Bean
和Bean類似,我們新建一個BeanForDagger的對象,其內容爲: public class BeanForDagger {
private String mName = null;
@Inject
public BeanForDagger() {
this.mName = "Dagger方式";
}
public String getName() {
return mName;
}
}
這個BeanForDagger和Bean的區別有兩點:1、mName的初始化名稱不同,這是爲了區分兩個對象
2、BeanForDagger的構造方法多了@Inject的註釋,它會告訴Dagger用這個方法來注入目標類
2.2、創建Component文件
然後我們我們新建一個BeanComponent的接口(文件),其內容如下: @Component
public interface BeanComponent {
void inject(MainActivity activity);
}
請注意,這個接口使用了@Component的註釋。
2.3、使用Dagger
經過上面修改之後,我們就可以使用Dagger來自動創建BeanForDagger對象了。首先在Activity中聲明該變量:
@Inject
BeanForDagger mBeanForDagger;
然後我們可以這樣使用該變量: private void testDagger() {
// 觸發Dagger機制
DaggerBeanComponent.create().inject(this);
if (mBeanForDagger != null) {
Log.d(TAG, "使用Dagger注入變量,mBeanForDagger Name:" + mBeanForDagger.getName());
}
}
運行之後的Log如下:這說明我們已經可以使用mBeanForDagger了,但是請注意,在Activity中(以及BeanComponent或BeanForDagger中),我們並沒有創建(new)BeanForDagger的對象。
也就是說,Dagger幫助我們完成了創建BeanForDagger對象的工作。
2.4、Dagger創建對象的過程
這一節我們通過最簡單的描述來簡單介紹一下Dagger是如何幫助我們創建BeanForDagger對象的。首先,在Activity的testDagger方法中,多了這麼一句:
DaggerBeanComponent.create().inject(this);
而這裏的DaggerBeanComponent是Dagger根據BeanComponent自動生成的,每一個XXXComponent都會生成對應的DaggerXXXComponent文件。當調用inject()時,DaggerBeanComponent就會掃描inject方法中的參數(當前就是Activity)中用@Inject標記的變量,對於當前的Activity來說,只有mBeanForDagger變量被標記。
找到這個需要被注入的變量後,發現他的類型是BeanForDagger,接下來,Dagger就會去搜索BeanForDagger的類,然後找到該類中用@Inject標記的構造方法,並用該構造方法來創建對象。
這個過程簡單來說就是這個步驟:
1、通過DaggerXXXComponent的Inject()觸發注入過程
2、搜索目標類中用@Inject標識的需要注入的對象
3、找到需要注入對象後,尋找該對象中用@Inject標識的構造方法,完成自動創建過程
2.5、用到的註釋
截至目前,我們用到了兩個註釋:@Inject和@Component,其中的Inject用來註釋需要注入的目標對象,以及用來注入的構造方法,而Component用來觸發注入機制。三、帶參數的構造方法
上面的使用過程雖然簡單,但是他的特點很明顯:需要被注入的對象的構造方法無需傳參數!因爲無需傳參,所以Dagger找到該構造方法後可以使用new BeanForDagger()的方法來完成創建工作。
那麼疑問就來了,如果這個構造方法需要參數時,怎麼辦?Dagger是否具有創建參數的能力?
比如我們的BeanForDagger對象的構造方法是這樣的:
@Inject
public BeanForDagger(ParamForDagger param) {
this.mName = param.mParamName;
}
那麼Dagger如何才能獲得ParamForDagger的參數呢?解決的方法很簡單,只需要在ParamForDagger的構造方法中標記@Inject即可,如這樣:
public class ParamForDagger {
String mParamName = null;
@Inject
public ParamForDagger() {
mParamName = "ParamName";
}
}
這樣一來,當Dagger在創建BeanForDagger時發現其構造方法需要ParamForDagger的對象,那麼Dagger就會遞歸查找ParamForDagger類中使用Inject標記的構造方法,找到後,先創建ParamForDagger,然後再用他來創建BeanForDagger。也就是說,Dagger具備遞歸創建對象的能力。
這個例子執行結果就是,將BeanForDagger中的mName初始化爲ParamForDagger中的值:ParamName,運行結果是這樣的:
四、一個疑問
上面的例子雖然介紹了有參數和無參數的注入,但他們都有兩個侷限:1、需要修改構造方法,添加@Inject的標識,但是對於一些jar包中的方法,或者第三方API中提供的方法,我們無法修改其源碼;
2、雖然構造方法中可以傳遞參數,但是實際上對這個參數也是有要求的,這個參數雖然會遞歸創建,但遞歸的最後一層的構造方法中還是無法傳參的;
要解決這兩個問題,請繼續看下一篇《Dagger2教程三之構造方法帶參數的情況(原)》