描述:17年最火的安卓網絡框架無疑是Retrofit2.0+Okhttp3.0,而中型項目架構最火的無疑是MVP,而今年Rxjava2.0也是異常的火爆,而Rxlifecycle的支持對使用rxjava出現內存泄露問題得到完美解決,對此,之前樓主對這幾種很火的技術封裝過一次,現在根據業務增加,進行了二次封裝。文章後面有本框架github地址。
一、所用技術
/ MVP 點擊打開鏈接
/ Okhttp3.0 點擊打開鏈接
/ Rxjava2.0 點擊打開鏈接
/ Rxlifecycle2.0 點擊打開鏈接
這裏就不細說這他們的基礎知識了,傳送門在上面。
二、架構
1.分包:目前demo裏面涉及到的包如下,如有其他的需求自定義包的名字就好,比如adapter包、custom包。
主要作用如下圖:
大家看到了上面這個多base想到了什麼,基類?抽象?接口?繼承?模版?答案是都對,不過還有一個沒說到,那就是泛型。java語言有泛型的支持我覺得是一件很棒的事情,有了它我相信很多人都不用手動去寫對象強轉了吧。
1.BaseView類
public interface BaseView {
}
它裏面爲空,沒有任何抽象方法,接口的作用有哪些還記得嗎?其中有一個作用就是標識作用,標識它是一個View的基類。2.BasePersenter
public abstract class BasePresenter<V extends BaseView>{
private V mView;
public V getView(){
return mView;
}
public void attachView(V v){
mView = v;
}
public void detachView(){
mView = null;
}
}
其中泛型V繼承於BaseView,也就是說我們傳的V泛型是必須繼承BaseView的,不然代碼檢查報錯。我們可以看到attachView和detachView兩個方法,當我們的view需要的時候就綁定p層,view銷燬的時候就與p層解綁。3.BaseModel
public class BaseModel<T> {
/**
* 封裝線程管理和訂閱的過程
* flag 是否添加progressdialog
*/
public void subscribe(Context context, final Observable observable, ObserverResponseListener<T> listener,
ObservableTransformer<T,T> transformer, boolean isDialog, boolean cancelable) {
final Observer<T> observer = new ProgressObserver(context, listener, isDialog,cancelable);
observable.compose(transformer)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
public void subscribe(Context context, final Observable observable, ObserverResponseListener<T> listener,
ObservableTransformer<T,T> transformer) {
subscribe(context,observable,listener,transformer,true,true);
}
}
BaseModel主要作用是封裝線程管理和訂閱的過程,當然也可以封裝數據庫的操作,這裏我就沒有寫出來了。4.BaseApi:
主要是封裝網絡對象retrofit,裏面可以設置網絡的連接超時和讀取時間、日誌攔截、緩存攔截、頭文件攔截等等。
5.Api及ApiService:
主要管理api接口。
6.BaseActivity、BaseFragment
BaseActivity引用P和V,泛型有兩個,必須分別繼承與BaseView與BasePresenter。當子類activity繼承於BaseAcivity時,getLayoutId方法獲取綁定佈局,然後createPresenter方法創建出p層,並將v視圖綁定。然後調用的init方法,我們就可以將初始化數據放到這裏。在activity銷燬時,將p層與v視圖解綁。Fragment用法也相似。
7.progress包:
ObserverResponseListener:請求監聽成功或者失敗。
ProgressCancelListener:請求監聽取消時。
ProgressDialogHandler:dialog出現與隱藏的一個Handler。
ProgressObserver(觀察者):繼承與Observer,監聽請求是否成功,
public class ProgressObserver<T> implements Observer<T>, ProgressCancelListener {
private static final String TAG = "ProgressObserver____ ";
private ObserverResponseListener listener;
private ProgressDialogHandler mProgressDialogHandler;
private Context context;
private Disposable d;
public ProgressObserver(Context context, ObserverResponseListener listener, boolean isDialog, boolean cancelable) {
this.listener = listener;
this.context = context;
if(isDialog){
mProgressDialogHandler = new ProgressDialogHandler(context, this, cancelable);
}
}
private void showProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
}
private void dismissProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
mProgressDialogHandler = null;
}
}
@Override
public void onSubscribe(Disposable d) {
this.d = d;
Log.e(TAG, "onSubscribe: ");
showProgressDialog();
}
@Override
public void onNext(T t) {
listener.onNext(t);//可定製接口,通過code回調處理不同的業務
}
@Override
public void onError(Throwable e) {
dismissProgressDialog();
Log.e(TAG, "onError: ", e);
//自定義異常處理
if(e instanceof ExceptionHandle.ResponeThrowable){
listener.onError((ExceptionHandle.ResponeThrowable)e);
} else {
listener.onError(new ExceptionHandle.ResponeThrowable(e, ExceptionHandle.ERROR.UNKNOWN));
}
if (e instanceof UnknownHostException) {
ToastUtil.showLongToast("請打開網絡");
} else if (e instanceof SocketTimeoutException) {
ToastUtil.showLongToast("請求超時");
} else if (e instanceof ConnectException) {
ToastUtil.showLongToast("連接失敗");
} else if (e instanceof HttpException) {
ToastUtil.showLongToast("請求超時");
}else {
ToastUtil.showLongToast("請求失敗");
}
}
@Override
public void onComplete() {
dismissProgressDialog();
Log.e(TAG, "onComplete: ");
}
@Override
public void onCancelProgress() {
Log.e(TAG, "requestCancel: ");
//如果處於訂閱狀態,則取消訂閱
if (!d.isDisposed()) {
d.dispose();
}
}
}
上面已經很清楚了,在onNext方法裏面獲取到響應再調用ObserverResponseListener接口的onNext回調到相應的P層,在觀察者的onError方法裏面根據自定義異常類,回調ObserverResponseListener接口的onError方法。自定義異常處理類就不多說了,裏面很詳細。這個觀察者實現了ProgressCancelListener的onCancelProgress方法,也就是當我們點擊回退鍵取消請求時,會調用此方法,在這裏我們拿到將在onSubscribe時給我們的Disposable消費者對象取消消費事件,此時將不會下發事件到觀察者的onNext方法,實現取消訂閱。到這裏,本框架基本就結束了。
下面講一下一個activity的例子:
1.創建契約類:爲什麼創建契約類?將一個業務所要用到的方法寫在一起不是便於管理嗎?以後需求增加或者改變,直接找契約類就行了。
V有三個方法:第一個是當數據請求成功時返回結果,第二個是失敗時發送信息通知界面,第三個是綁定完成Observable發佈的事件和當前組件綁定,實現生命週期同步,從而實現當前組件生命週期結束時,自動取消對Observable訂閱。
P有一個方法:設置請求參數及是否顯示dialog與該dialog是否能被取消。
2.創建實體類:這就不用說了。
3.創建model層:
我測試用的這個方法本來是想用我們公司的測試登錄接口的,但是可能會改變,所以我就用的一個開源查詢快遞的api,可以直接使用通用的請求方法,故此直接繼承BaseModel類,並調用subscribe這個方法即可。
4.創建Persenter層:
P層繼承契約類裏面寫好的抽象P層,實現其中的login抽象方法,在P層構造中實例化M層對象。當P層的login方法被調用時,M層調用它自己的login方法進行網絡請求。實現ObseriverResponseListener的請求成功與失敗方法。當觀察者走到了它的onNext方法時,它將會回調ObseriverResponseListener的onNext方法到P層,P層拿到數據結果,調用與之綁定的V層方法result傳值給頁面以更新數據,相應的onError方法也是如此理解即可。
5.activity頁面:
如圖所示:
頁面只需要繼承BaseActivity並傳入業務邏輯相關的契約類V和P,然後實現接口V的方法。
大家應該理解得到,首先設置佈局,創建該業務的P層實例,創建V層。然後就是等待按鈕點擊,調用P層的login方法,P層調用getview方法的bindlifecycle方法綁定生命週期,然後等待P層返回數據和Msg。
--->問題1:如何在一個頁面實現多個請求
1.在Contract層的Presenter建立抽象方法2
2.在Module層建立方法,在ApiService層建立相應的接口;
3.在Activity實現Contract層的接口;
在Activity調用getPresenter().logout(map2,false,true),完成頁面請求多個接口了。
--->問題2:業務量少的時候,不需要用P層的情況下,怎麼使用rx來管理請求
1.創建Activity後繼承BaseActivity,不需要傳入泛型等等;
2.實現BaseActivity的createPresenter、createView方法時返回null,此時也需要一個module層來提供網絡請求等的方法;
3.在Activity直接調用module層的方法進行請求即可。
以上例子是很簡單的,在實際項目過程中,業務邏輯肯定相對複雜的多,不過大致的網絡方面的問題基本上此框架即可完成。
閱讀到此,本文也結束了,有問題issues,希望能有star哦。因爲本人堅持開源原則,所以這裏只放了github。https://github.com/senonwx/mvpretrofitrx.git