關於Dagger2是啥,用法網上已經有很多了。不過聽說你已經很多次Dagger2從入門到放棄了,來來,讓我這個老中醫給你治一治。老夫手法純熟,不會讓你有任何痛苦的,放心讀下去吧。
本文同步自 博主的私人博客 wing的地方酒館
診斷
咳咳,看你這架勢病的不清,應該是陌生代碼恐懼症,你看看下面的代碼。會不會害怕。
private ShipDetailPresenter mShipDetailPresenter;
mShipDetailPresenter = DaggerShipDetailComponent.builder()
.shipDetailModule(new ShipDetailModule(this, this))
.build()
.inject();
喂!!!你怎麼跑了,快回來,還沒治病呢!!
用法回顧(注入第一式)
首先,對於一般來說,想創建一個對象,我們肯定採取new的形式:
mShipDetailPresenter = new ShipDetailPresenter(context,shipDetailView);
但是這樣耦合度較高,presenter的變化受限於Activity,也就是說假如我們的presenter的參數變成三個了,又要改Activity代碼。所以使用Dagger2的好處就很明顯了,如果改了構造器,只需要改對應的Module就可以。
@Module
上面提到了Module,這是什麼呢?其實這是一個提供參數的地方,將new Presenter所需要的參數,寫到這裏面來了。看示例代碼:
@Module //註解說明這是Module
public class ShipDetailModule {
private ShipDeatilContract.View mView;
private Context mContext;
public ShipDetailModule(ShipDeatilContract.View mView, Context mContext) {
this.mView = mView;
this.mContext = mContext;
}
//註解說明Provide View 既提供View參數
@Provides ShipDeatilContract.View getView(){
return mView;
}
//註解說明Provide Context 既提供Context參數
@Provides Context getContext(){
return mContext;
}
}
這是Module的寫法,就是把new Presenter(Context,View)寫到了裏面。
@Inject
Module怎麼知道presenter構造器需要幾個參數呢,答案是@Inject ,只需要在Presenter的構造器註解@Inject
public class ShipDetailPresenter implements ShipDeatilContract.Presenter {
Context context;
ShipDeatilContract.View shipDetailViewInterface;
//告知構造求所需參數
@Inject
public ShipDetailPresenter(Context context,ShipDeatilContract.View shipDetailViewInterface){
this.context=context;
this.shipDetailViewInterface=shipDetailViewInterface;
}
@Component
連接Presenter和Module的東東,我們只需要寫一個接口,來返回Presenter對象,Dagger2就會自動生成對應的對象給我們。
//註解標註Component 並且告知需要的module是什麼
@Component(modules = ShipDetailModule.class)
public interface ShipDetailComponent {
//接口的方法,返回presenter
ShipDetailPresenter inject();
}
最終聯繫
現在看回第一段代碼
private ShipDetailPresenter mShipDetailPresenter;
mShipDetailPresenter = DaggerShipDetailComponent.builder()
.shipDetailModule(new ShipDetailModule(this, this))
.build()
.inject();
DaggerShipDetailComponent這個類是build之後Dagger2自動爲我們生成的類,查看源碼它實現了ShipDetialComponent這個方法,所以inject()函數自然會爲我們返回一個presenter來啦。
用法回顧(注入第二式)
你可能犯嘀咕了,你這種寫法不科學!跟我看到的不一樣。咳咳,不要急,老夫再給你說另一種用法。這種方法的代碼如下:
@Inject ShipDetailPresenter mShipDetailPresenter;
DaggerShipDetailComponent.builder()
.shipDetailModule(new ShipDetailModule(this, this))
.build()
.inject(this);
對應的Component爲:
public interface ShipDetailComponent {
void inject(ShipDetailActivity);
}
其他的寫法都一樣。 此時你心裏肯定犯嘀咕了,麼麼的,你剛纔說是inject()返回presenter所以可以賦值,這個void你怎麼解釋! 是不是又要放棄拉,年輕人,不要輕言放棄,聽老夫一言。
想要知道Dagger2 怎麼做的那麼神奇,必須知道他的原理,原理怎麼看?當然是看他生成的代碼唄!
Dagger2原理
第一式解密
首先看第一種方法的原理,找到DaggerShipDetailComponent 發現代碼如下:
public final class DaggerShipDetailComponent implements ShipDetailComponent {
private Provider<Context> getContextProvider;
private Provider<ShipDeatilContract.View> getViewProvider;
private Provider<ShipDetailPresenter> shipDetailPresenterProvider;
/** 去處多行代碼**/
}
可以看到Component確實實現了我們定義的Component,所以他的inject()方法肯定是返回了一個presenter
@Override
public ShipDetailPresenter inject() {
return shipDetailPresenterProvider.get();
}
老夫沒有騙你吧,至於這個provider如何拿到的newPresenter,這裏給你留個家庭作業。現在應該有些頭緒了吧,Dagger2沒有想象中那麼難,對不對?接下來看看讓你懵逼的第二式。
第二式
直接看生成的代碼!在DaggerShipDetailComponent發現了
public void inject(ShipDetailActivity activity) {
shipDetailsMembersInjector.injectMembers(activity);
}
繼續往下看,看到了一個init方法
private void initialize(final Builder builder) {
this.getContextProvider = ShipDetailModule_GetContextFactory.create(builder.shipDetailModule);
this.getViewProvider = ShipDetailModule_GetViewFactory.create(builder.shipDetailModule);
//工廠生成provider 用來提供presenter
this.shipDetailPresenterProvider =
ShipDetailPresenter_Factory.create(getContextProvider, getViewProvider);
//生成MembersInjector
this.shipDetailActivityMembersInjector =
ShipDetailActivity_MembersInjector.create(shipDetailPresenterProvider);
}
接下來順藤摸瓜,找到了ShipDetailActivity_MembersInjector,只看關鍵部分源碼
public final class ShipDetailActivity_MembersInjector
implements MembersInjector<ShipDetailActivity> {
//進行注入操作
public static void injectShipDetailPresenter(
ShipDetailActivity instance, Provider<ShipDetailPresenter> shipDetailPresenterProvider) {
instance.shipDetailPresenter = shipDetailPresenterProvider.get();
}
}
相信聰明的你已經明白了,爲什麼返回void還能注入,不知道你有沒有發現,第二式的presenter沒有用private修飾,在injectShipDetailPresenter(ShipDetailActivity,Provider)的時候將 activity.presenter = Proivider.get()!
如果讓我用兩個字來形容的話,我只能說
太他媽精彩
嘛,這次會診就到這裏吧,回家記得勤加鍛鍊,早日康復,再見。