今天玩一下Dagger2,個人第一感覺就是,一種本來挺好理解的東西,硬生生被玩着複雜和變得難以理解了,哈哈,也有可能是自己技術水平不夠,不說廢話了,下面開始記錄一下我的學習心得。
Dagger2,官方的說明是A fast dependency injector for Android and Java,翻譯成國語就是“Android和Java的快速依賴注入器。”
一、什麼是依賴注入
下面先看一個例子,比如我假設有一個類——Ferry(船),一個類——Paddle(槳),現在我們需要定義一個船類,並且在船類中定義一個變量槳類,我們會這樣做:
class Ferry{
Paddle paddle = new Paddle();
Ferry();
}
上面這種寫法很完美的解決問題,但是現在如果Ferry類的需求改了,需要加入一個參數,那麼我們是不是要同時修改Ferry類和Paddle類,這樣看來Ferry類是不是很依賴Paddle類,Paddle類一改,Ferry類就要跟改。那麼我們的程序員就想出一個方法,不在Ferry類中新建Paddle類,而是在外面把Paddle類注入進入,比如這樣:
class Ferry{
Paddle paddle;
Ferry(Paddle paddle){
this.paddle = paddle;
}
}
上面這種這種做法就是依賴注入,把所依賴的Paddle類從外面把它注入進來,而不是在Ferry類中自己建立。而Dagger2就是用來做上面依賴注入這一步的,他的基本原理就是這麼簡單,但是跟上面不同,他不是直接以構造方法的參數形式注入的,下面我會詳細解釋。
補充一下:依賴注入其實是一種方法,他的主要思想叫做控制反轉(Inversion of Control,英文縮寫爲IoC),控制反轉還有另一種方法叫做依賴查找,想了解詳細的,自行百度。
二、環境搭建
怎麼將Dagger2接入AS工程中,只需要兩步:
1、在主工程下的build.gradle中加入classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
2、然後在app模塊分別加入:
apply plugin: 'com.neenbedankt.android-apt'
compile ‘com.google.dagger:dagger:2.11’
apt‘com.google.dagger:dagger-compile:2.11’
provided ‘org.glassfish:javax.annotation:10.0-b28’
這樣就完成Dagger2的Gradle配置,如果你是高版本的AS這樣配置可能會出現問題,請參考我的另一篇博客
http://blog.csdn.net/m0_37605407/article/details/79091389
三、現在開始玩最簡單的Dagger2
下面這些步驟都是基本固定,只要按照這樣的步驟就可以實現Dagger2構架的接入。
我們接着上面船和槳的例子,用Dagger2實現依賴注入:
//船類
public class Paddle {
@Override
public String toString() {
return "我是船";
}
}
//Paddle的提供類
@Module
public class MainModule {
@Provides
public Paddle getPaddle() {
Paddle paddle = new Paddle();
return paddle;
}
}
//建立一個接口,連接Paddle類和Ferry類的關係
@Component(modules=MainModule.class)
public interface MainComponent {
void inject(FerryActivity ferryActivity);
}
然後編譯,你會驚喜發現自動多了兩個中間類。
現在可以在Ferry類中進行依賴注入了
public class FerryActivity extends AppCompatActivity {
@Inject
Paddle paddle;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainComponent build = DaggerMainComponent.builder().mainModule(new MainModule()).build(); //關鍵代碼1
build.inject(this); //關鍵代碼2
Log.d("Dagger2",paddle.toString() );
}
}
到這裏就完成了整個步驟,可以成功打印出 03-21 23:18:18.918 28286-28286/? D/Dagger2: 我是船
我們開始從代碼中去看Dagger2到底幹些什麼?
首先,在FerryActivity中調用關鍵代碼1,新建了DaggerMainComponent類中的靜態內部類Builder,然後把一個新建MainModule類傳遞給Builder,最後新建一個帶有MainModule對象的DaggerMainComponent類
public static final class Builder {
private MainModule mainModule;
private Builder() {}
public MainComponent build() {
if (mainModule == null) {
this.mainModule = new MainModule();
}
return new DaggerMainComponent(this);//新建一個帶有MainModule對象的DaggerMainComponent類
}
public Builder mainModule(MainModule mainModule) {
this.mainModule = Preconditions.checkNotNull(mainModule);//FerryActvity調用這個方法傳遞進去MainModule對象
return this;
}
}
然後,在DaggerMainComponent類的構造方法中
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);//在這步裏面做了關鍵步驟
}
private void initialize(final Builder builder) {
this.getPaddleProvider = MainModule_GetPaddleFactory.create(builder.mainModule);
this.ferryActivityMembersInjector = FerryActivity_MembersInjector.create(getPaddleProvider);
}
我們先來看,this.getPaddleProvider = MainModule_GetPaddleFactory.create(builder.mainModule)這一步幹了些什麼?
public static Factory<Paddle> create(MainModule module) {
return new MainModule_GetPaddleFactory(module);
}
上面代碼中,新建了MainModule_GetPaddleFactory對象,然後傳遞給了FerryActivity_MembersInjector的靜態方法create。
public static MembersInjector<FerryActivity> create(Provider<Paddle> paddleProvider) {
return new FerryActivity_MembersInjector(paddleProvider);
}
上面代碼中,新建了一個帶有MainModule_GetPaddleFactory對象的FerryActivity_MembersInjector類。然後在FerryActivity中調用了關鍵代碼2
調用了DaggerMainComponent類中的inject方法
@Override
public void inject(FerryActivity ferryActivity) {
ferryActivityMembersInjector.injectMembers(ferryActivity);
}
public void injectMembers(FerryActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.paddle = paddleProvider.get();
}
public Paddle get() {
return Preconditions.checkNotNull(
module.getPaddle(), "Cannot return null from a non-@Nullable @Provides method");
}
哈哈,到這裏真相大白了,FerryActivity.paddle = Module.getPaddle,其實啊,弄了這麼久,Dagger就是做了這麼一件事情。
今天先到這裏,上面的出現的一些註解,只是爲了讓apt編譯出中間的類,但是對於這些註解的特殊用法,我還沒有去深究,關於Dagger2的學習筆記我會在接下來的博客繼續更新。