Dagger2的化簡學習總結
Dagger2是一款非常優秀的依賴注入框架,依然簡單去講,首先必須明確一個理念:依賴注入是實現控制反轉的方式之一,所以先普及一下依賴注入和控制反轉的兩個基本概念:
控制反轉:簡單的說就是如果你需要建立(new),那麼別自己手敲,把它交給三方框架去做。控制反轉是面向物件程式設計的一種設計模式,目的就是降低程式碼的耦合性。
依賴注入:拿Android打比方,一個Activity中可能需要很多的類例項,中規中矩的寫法就是需要什麼就new什麼,咣咣一頓new,用依賴注入的寫法的話,只需要寫明特定的框架標識,讓依賴注入的框架往Activity中自動增加需要new的東西就行了,不用自己去寫例項化的物件了。
Dagger2多用於Android的MVP模式,最大的好處是降低了程式碼的耦合性,避免了因為A這個類的程式碼改了,所以B.class也要更改的關聯改動的現象,按照Dagger的語法標識好,寫好相應的interface介面,Dagger就會自動生成目的碼用來提供依賴注入的操作。Dagger2的整合使用也要先說幾個涉及的基本概念詞:依賴 ,需求者, 紐帶。先說理論性的描述,在列舉完理論之後會用Demo的程式碼去具體分析。
需求者
依賴:用虛擬碼去理解,兩個類老虎類和牙齒類,老虎生存捕食,牙齒是被老虎依賴的關係
class 牙齒{
public 牙齒() {
}
}
class 老虎 {
牙齒 b;
public 老虎() {
b = new 牙齒();
}
}
如果用Dagger的格式依賴注入的話,那麼上述程式碼就會變成下圖。老虎的@Inject宣告在屬性上,說明它是一個需求者,牙齒的@Inject在建構函式上,說明牙齒是一個依賴,這種是最簡單的依賴提供形式。
class 牙齒{
@Inject
public 牙齒() {
}
}
class 老虎 {
@Inject
牙齒 b;
}
依賴一般有2種方式,一是通過@Inject建構函式的方式提供,二是通過Module的方式提供。但是光有依賴和需求者是不夠的,必須有一個紐帶來維繫才能讓Dagger2正常的工作。
紐帶:@Component來標識,被標註了Component的介面在編譯時會產生相應的類的例項來作為提供依賴方和需求者之間的紐帶。下面是紐帶的三種常見寫法:
@Component()
public interface Platform {
ZhaiNan waimai(); //帶返回值就算是一種依賴的提供
}
@Component(modules = ShangjiaAModule.class) //@Component()裡的.class就是提供的涉及三方庫的依賴
public interface WaimaiPingTai {
ZhaiNan waimai();
}
@Component(modules = ShangjiaAModule.class)
public interface WaimaiPingTai {
void zhuru(MainActivity mainActivity); //在方法中傳入型別引數。目的是針對這個引數物件進行依賴注入
}
值得注意的是,dagger2有兩種@inject提供依賴,和provide提供依賴。Dagger2 依賴查詢的順序是先查詢 Module 內所有的 @Provides 提供的依賴,如果查詢不到再去查詢 @Inject 提供的依賴。下面還是用Demo的程式碼去一點一點的分析理解Dagger2如何在MVP專案中實戰,先看效果圖:
效果圖
Demo實現的效果很簡單,點選介面上的搜尋按鈕,會發送http協議獲取某個城市的經緯度,當獲取到http請求回執後,反序列化Json,然後重新繪製介面,顯示經緯度。從MVP的模式去講,這個包含搜尋Button的,點選搜尋後彈出的轉圈等待介面就是View層,當響應點選事件之後,View層就會通知Presenter層,讓Presenter去傳送獲取經緯度的http協議,並且在Presenter中監聽http協議的回執,若協議收發成功,那麼presenter就會通知View層去重新繪製UI,Dagger2用來依賴註解Presenter,傳送協議的等待轉圈dialog和Retrofit2.0。
下面貼出具體程式碼進行理解 ,先是依賴注入Presenter部分 :
/**
* Created by xjc on 2018/11/26.
*/
public abstract class IBaseActivity<T extends BasePresenter> extends BaseActivity implements Stateful {
@Inject
protected T mPresenter;
private Unbinder bind;
QMUITipDialog tipDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind = ButterKnife.bind(this);
initView();
initInject();
if (mPresenter != null)
mPresenter.attachView(this);
loadData();
}
public void createLoading(){
tipDialog = new QMUITipDialog.Builder(this)
.setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
.setTipWord("正在載入")
.create();
tipDialog.show();
}
public void dismiss(){
if (tipDialog != null)
tipDialog.dismiss();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bind != null) {
bind.unbind();
}
if (mPresenter!=null){
mPresenter.detachView();
}
}
protected abstract void loadData();
protected abstract void initView();
/**
* dagger2注入
*/
protected abstract void initInject();
每一個VIew介面都需要Presenter作為中介,如此以來專案中將Presenter提到介面的基類IBaseActivity中通過依賴注入的方式建立,@Inject 就是Dagger2的識別符號,加在了屬性之上說明這個IBaseActivty是需求者的身份,而Presenter是作為一個依賴被注入,接下來看Presenter 的實現類:
public class MainPresenterImpl extends BasePresenter<MainPresenter.View> implements MainPresenter.Model{
private ApiHttpService apiHttpService;
@Inject
public MainPresenterImpl(ApiHttpService apiHttpService) {
this.apiHttpService = apiHttpService;
}
@Override
public void getLonLat() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("a","大連");
} catch (JSONException e) {
e.printStackTrace();
}
invoke(apiHttpService.fetchLocation(jsonObject.toString()),new Callback<LocationResponseBean>(){
@Override
public void onResponse(LocationResponseBean bean){
mView.refreshViewMistakeIntruductionList(bean);
}
});
}
}
注意在建構函式上也有 @Inject的標識,這說明了告訴了Dagger2框架Presenter的身份是一個依賴。當build專案後可以在編譯生成的檔案中查詢到Dagger2生成的檔案,其中以_MembersInjector結尾的就是上面所說的注入器,然後就能在頁面程式碼進行依賴注入的操作:
下面是為了http通訊的Retrofit依賴注入的部分:
/**
* Created by quantan.liu on 2017/4/8.
*/
@Singleton
@Component(modules = { ApiHttpModule.class})
public interface MainComponent {
void injectMain(MainActivity activity);
}
這是紐帶的程式碼,從而可知依賴是ApiHttpModule.class, 根據上面所列舉的紐帶第三種寫法可知是往MainActivity注入,需求者是MainActivity,接下來看依賴的程式碼:
/**
* Created by xjc on 2018/11/26.
*/
@Module
public class ApiHttpModule extends BaseHttpModule {
@Singleton
@Provides
Retrofit provideApiHttpRetrofit(Retrofit.Builder builder, OkHttpClient client) {
return createRetrofit(builder, client, ApiHttpService.API_URL);
}
@Singleton
@Provides
ApiHttpService provideApiHttpService( Retrofit retrofit) {
return retrofit.create(ApiHttpService.class);
}
}
/**
* Created by xjc on 2018/11/26.
*/
@Module
public class BaseHttpModule {
/**
* 提供http的幫助依賴 以下部分現在都放在子類。
* @return
*/
@Singleton
@Provides
Retrofit.Builder provideRetrofitBuilder() {
return new Retrofit.Builder();
}
@Singleton
@Provides
OkHttpClient.Builder provideOkHttpBuilder() {
return new OkHttpClient.Builder();
}
@Singleton
@Provides
OkHttpClient provideClient(OkHttpClient.Builder builder) {
//設定超時
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//錯誤重連
builder.retryOnConnectionFailure(true);
return builder.build();
}
protected Retrofit createRetrofit(Retrofit.Builder builder, OkHttpClient client, String url) {
return builder
.baseUrl(url)
.client(client)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(AESGsonConverterFactory.create())
.build();
}
}
最後在主介面中通過Dagger2自動生成的程式碼檔案進行依賴注入,就完成了依賴注入的所有操作:
DaggerMainComponent.builder().apiHttpModule(new ApiHttpModule()).build().injectMain(this);
Demo已打包上傳:https://download.csdn.net/download/crystal_xing/10811027