手寫Rxjava+Retrofit+Mvp
今天來寫寫我的第一篇部落格,分享一下自己手寫的Rxjava+Retrofit+Mvp,幫助大家學習,要是有哪些寫的不好的地方可以提出來,我虛心接受。
關于什麼是Rxjava和Retrofit,兩者結合的好處我這裡就不在一一概述了,網上有很多大牛寫的都很好,這裡推薦幾篇比較好的博文,大家可以去參考一下,一篇是扔物線大牛寫的給Android 開發者的RxJava 詳解和Android 優雅的讓RxJava2.0+Retrofit2.0結合使用。先附上gradle的依賴,以免到時候小夥伴們找到的類會有偏差。
//rxjava +retrofit
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合rxjava2
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'//攔截器
本文重點講述的事如何搭建mvp架構,因為自己比較喜歡架構這一塊,尤其是mvp設計模式,簡單明了的代碼風格和清晰的體系結構受廣大程式員的喜歡,最近有去研究了這個模式,加了一些自己的了解,下面就把自己所感所悟分享出來,有哪些寫的不好的地方和錯誤歡迎指出。
什麼是mvp
先上個圖友善大家的了解
mvp(model view presenter)是一種設計模式,在mvc(model view controller)的基礎上進行了優化,使得在代碼結構上非常的幹淨和整潔,mvp和mvc相比,mvc的View,controller和model全都寫在一個activity裡,我相信很多老的android應用應該都是這樣寫的,這樣寫的代碼比較臃腫,會造成一個界面産生幾千行代碼的可能,維護起來非常的困難。而mvp架構在代碼風格上就完勝mvc,它把View和Model這兩塊抽離出來,放在單獨的子產品裡,通過presenter這個對象進行互動,降低了代碼的耦合度。
一.什麼是model
model英文翻譯過來就是資料模型,像我們平日裡通過網絡請求得到的json資料要通過一個實體類進行儲存,這個實體類就是我們所說的model資料模型,裡面包含業務邏輯這塊。當然model你也可以這麼去了解,他是擷取網絡資料的一個類。
如何搭建model層
一.搭建Disposable管理類
1.定義Disposable接口
package com.lcp.lcplibrary.mvp.disposable;
import io.reactivex.disposables.Disposable;
/**
* Created by lcp on 2018/6/16.
*/
public interface IDisposable {
//添加
void add(Disposable subscription);
//取消
void cancel(Disposable t);
//取消所有
void cancelall();
}
2.定義一個Disposable的實作類DisposableManager
package com.lcp.lcplibrary.mvp.disposable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
/**
* Created by lcp on 2018/6/16.Disposable管理類
*/
public class DisposableManager implements IDisposable {
private static DisposableManager subscriptionManager;
private CompositeDisposable mDisposables;
private DisposableManager() {
if (mDisposables == null) {
mDisposables = new CompositeDisposable();
}
}
@Override
public void add(Disposable disposable) {
if (disposable == null) return;
mDisposables.add(disposable);
}
@Override
public void cancel(Disposable disposable) {
if (mDisposables != null) {
mDisposables.delete(disposable);
}
}
@Override
public void cancelall() {
if (mDisposables != null) {
mDisposables.clear();
}
}
public static DisposableManager getInstance() {
if (subscriptionManager == null) {
subscriptionManager = new DisposableManager();
}
return subscriptionManager;
}
}
二.定義異常處理類
package com.lcp.lcplibrary.mvp.error;
/**
* Created by lcp on 2018/6/16.錯誤資訊的實體類
*/
public class ErrorBodyDTO {
private String errCode;
private String errMsg;
public String getErrCode() {
return errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}
package com.lcp.lcplibrary.mvp.error;
import android.net.ParseException;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import org.json.JSONException;
import java.io.IOException;
import java.net.ConnectException;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
/**
* Created by lcp on 2018/6/16.異常處理類
*/
public class ExceptionHandle {
private static final int UNAUTHORIZED = ;
private static final int FORBIDDEN = ;
private static final int NOT_FOUND = ;
private static final int REQUEST_TIMEOUT = ;
private static final int INTERNAL_SERVER_ERROR = ;
private static final int BAD_GATEWAY = ;
private static final int SERVICE_UNAVAILABLE = ;
private static final int GATEWAY_TIMEOUT = ;
private static final int FAIL_QUEST = ;//無法使用請求的内容特性來響應請求的網頁
private static final int BAD_REQUEST = ;
private static ResponseBody body;
public static ResponeThrowable handleException(Throwable e) {
ResponeThrowable ex;
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
switch (httpException.code()) {
case UNAUTHORIZED:
break;
case FORBIDDEN:
ex.message = "伺服器已經了解請求,但是拒絕執行它";
break;
case NOT_FOUND:
ex.message = "伺服器異常,請稍後再試";
break;
case REQUEST_TIMEOUT:
ex.message = "請求逾時";
break;
case GATEWAY_TIMEOUT:
case INTERNAL_SERVER_ERROR:
ex.message = "伺服器遇到了一個未曾預料的狀況,無法完成對請求的處理";
break;
case BAD_REQUEST:
break;
case BAD_GATEWAY:
case SERVICE_UNAVAILABLE:
case FAIL_QUEST:
body = ((HttpException) e).response().errorBody();
try {
String message = "";
if (body != null) {
message = body.string();
}
Gson gson = new Gson();
ErrorBodyDTO globalExceptionDTO = gson.fromJson(message, ErrorBodyDTO.class);
if (globalExceptionDTO.getErrMsg() != null) {
ex.message = globalExceptionDTO.getErrMsg();
} else {
ex.message = "";
}
} catch (IOException e1) {
e1.printStackTrace();
}
break;
default:
ex.message = "網絡錯誤";
break;
}
return ex;
} else if (e instanceof ServerException) {
ServerException resultException = (ServerException) e;
ex = new ResponeThrowable(resultException, resultException.code);
ex.message = resultException.message;
return ex;
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException) {
ex = new ResponeThrowable(e, ERROR.PARSE_ERROR);
ex.message = "解析錯誤";
return ex;
} else if (e instanceof ConnectException) {
ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR);
ex.message = "連接配接失敗";
return ex;
} else if (e instanceof javax.net.ssl.SSLHandshakeException) {
ex = new ResponeThrowable(e, ERROR.SSL_ERROR);
ex.message = "證書驗證失敗";
return ex;
} else if (e instanceof java.net.SocketTimeoutException) {
ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
//ex.message = "連接配接逾時";
ex.message = "目前網絡連接配接不順暢,請稍後再試!";
return ex;
} else if (e instanceof java.net.UnknownHostException) {
ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
ex.message = "網絡中斷,請檢查網絡狀态!";
return ex;
} else if (e instanceof javax.net.ssl.SSLException) {
ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
ex.message = "網絡中斷,請檢查網絡狀态!";
return ex;
} else if (e instanceof java.io.EOFException) {
ex = new ResponeThrowable(e, ERROR.PARSE_EmptyERROR);
ex.message = "1007";
return ex;
} else if (e instanceof NullPointerException) {
ex = new ResponeThrowable(e, ERROR.PARSE_EmptyERROR);
ex.message = "資料為空,顯示失敗";
return ex;
} else {
ex = new ResponeThrowable(e, ERROR.UNKNOWN);
ex.message = "未知錯誤";
return ex;
}
}
/**
* 約定異常
*/
private class ERROR {
/**
* 未知錯誤
*/
private static final int UNKNOWN = ;
/**
* 解析錯誤
*/
private static final int PARSE_ERROR = ;
/**
* 解析no content錯誤
*/
private static final int PARSE_EmptyERROR = ;
/**
* 網絡錯誤
*/
private static final int NETWORD_ERROR = ;
/**
* 協定出錯
*/
private static final int HTTP_ERROR = ;
/**
* 證書出錯
*/
private static final int SSL_ERROR = ;
/**
* 連接配接逾時
*/
private static final int TIMEOUT_ERROR = ;
private static final int LOGIN_ERROR = -;
private static final int DATA_EMPTY = -;
}
public static class ResponeThrowable extends Exception {
private int code;
public String message;
private ResponeThrowable(Throwable throwable, int code) {
super(throwable);
this.code = code;
}
private ResponeThrowable(String message, int code) {
this.code = code;
this.message = message;
}
}
private class ServerException extends RuntimeException {
private int code;
private String message;
private ServerException(int code, String message) {
this.code = code;
this.message = message;
}
}
}
三.搭建Model層
1.搭建BaseModel
在這個類裡進行對象的訂閱,被觀察者訂閱觀察者
package com.lcp.lcplibrary.mvp.model;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by lcp on 2018/6/13.訂閱
*/
public class BaseModel<T> {
public void subscribe(Observable<T> observable, Observer<T> observer) {
observable
//請求完成後在主線程更新UI
.observeOn(AndroidSchedulers.mainThread())
//請求資料的時間發生在io線程
.subscribeOn(Schedulers.io())
.subscribe(observer);
}
}
定義泛型T,為你要生成的實體類。
2.建立一個Observer實作類去實作io.reactivex.Observer接口
重寫onSubscribe,onNext和onError回調方法,自行處理傳回的資料
package com.lcp.lcplibrary.mvp.model;
import com.lcp.lcplibrary.mvp.error.ExceptionHandle;
import io.reactivex.disposables.Disposable;
/**
* Created by lcp on 2018/6/16.觀察者
*/
public abstract class MyObServer<T> implements io.reactivex.Observer<T> {
@Override
public void onSubscribe(Disposable d) {
OnDisposable(d);
}
@Override
public void onNext(T t) {
OnSuccess(t);
}
@Override
public void onError(Throwable e) {
//自定義異常的傳遞
OnFail(ExceptionHandle.handleException(e));
Onfinish();
}
@Override
public void onComplete() {
Onfinish();
}
public abstract void OnSuccess(T t);
public abstract void OnFail(ExceptionHandle.ResponeThrowable e);
public abstract void Onfinish();
public abstract void OnDisposable(Disposable d);
}
- 通過泛型T,可以随機改變你想要的類型,傳入什麼類型,得到的就是什麼類型
- 定義四個抽象方法OnSuccess,OnFail,Onfinish,OnDisposable,在onSubscribe,onComplete,onNext和onError回調時使用,讓MyObserver的實作類去重寫方法
- 相當于給Observer做了一層封裝
二.什麼是View
View英文翻譯過來是視圖的意思,在mvp裡面它所擔當的角色是界面上的顯示效果,比如網絡開始請求時,你要顯示彈窗,網絡結束時你要結束彈窗,網絡錯誤時你要顯示Toast,這些都是View上的東西,說白了就是Ui線程上所要做的操作。如何搭建View層
一.定義一個自己所需要的View
1.寫一個BaseView接口IBaseView
我這裡就簡單定義兩個方法,一個是顯示彈窗,一個是消失。
package com.lcp.lcplibrary.mvp.view;
/**
* Created by lcp on 2018/6/12.界面資料加載的處理
*/
public interface IBaseView {
void showLoading();
void dismissLoading();
}
2.定義一個IMvpView,去繼承IBaseView
package com.lcp.lcplibrary.mvp.view;
/**
* Created by lcp on 2018/6/12 0011.資料加載的回調方法
*/
public interface IMvpView<T> extends IBaseView {
void onSuccess(T t);
void onfailed(String msg);
}
- 通過泛型,拿到自己想要的實體類
三.什麼是presenter
presenter其實就是model和View的中介,mvp中的核心其實就是presenter,這也是和mvc最大的差別,mvc沒有了controller,view和model照樣可以進行互動,而mvp沒有了presenter,view和model是不能進行互動的。總之presenter是mvp裡比較重要的一塊内容。
如何搭建presenter
一.搭建主Presenter接口
在這裡接口裡定義presenter的生命周期
package com.lcp.lcplibrary.mvp.presenter;
/**
* Created by lcp on 2018/6/12.主Presenter接口,Presenter的生命周期
*/
public interface IBasePresenter<V> {
void onCreate();
void onDestory();
void attachView(V v);
void detachView();
}
二.定義一個IBasePresenter的實作類
整個mvp架構的核心部分
package com.lcp.lcplibrary.mvp.presenter;
import com.lcp.lcplibrary.mvp.disposable.DisposableManager;
import com.lcp.lcplibrary.mvp.error.ExceptionHandle;
import com.lcp.lcplibrary.mvp.model.BaseModel;
import com.lcp.lcplibrary.mvp.model.MyObServer;
import com.lcp.lcplibrary.mvp.view.IMvpView;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
/**
* Created by lcp on 2018/6/11 0011.主presenter的實作類,用來處理view和model之前的互動
*/
public class BasePresenter<T, V extends IMvpView<T>> implements IBasePresenter<V> {
private BaseModel<T> mbaseModel;
private V mbaseView;
public BasePresenter() {
}
public void getData(Observable<T> observable) {
mbaseView.showLoading();
mbaseModel.subscribe(observable, new MyObServer<T>() {
@Override
public void OnSuccess(T t) {
mbaseView.onSuccess(t);
}
@Override
public void OnFail(ExceptionHandle.ResponeThrowable e) {
mbaseView.onfailed(e.message);
}
@Override
public void Onfinish() {
mbaseView.dismissLoading();
}
@Override
public void OnDisposable(Disposable d) {
DisposableManager.getInstance().add(d);
}
});
}
@Override
public void onCreate() {
mbaseModel = new BaseModel<>();
}
@Override
public void onDestory() {
cancelAll();
}
@Override
public void attachView(V v) {
mbaseView = v;
}
private void cancelAll() {
DisposableManager.getInstance().cancelall();
}
@Override
public void detachView() {
mbaseView = null;
}
}
- 定義泛型,層層嵌套,限制類型
- 重寫方法,在生命周期裡進行對象的建立和銷毀
- 在getData方法裡實作model和View的互動,最後把資料傳遞給外部
四.MvpActivity
它作為所有想實作mvp體系的Activity的基類,搭建它是為了以後快速的實作
如何搭建MvpActivity
一.建立BaseActivity
大家在項目中經常用到的基類,我這裡簡單寫兩個方法
package com.lcp.lcplibrary.mvp.view;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
/**
* Created by lcp on 2018/6/28.activity的基類
*/
public class BasicActivity extends Activity {
private ProgressDialog progressDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void showLoading() {
if (progressDialog == null) {
progressDialog = new ProgressDialog(this);
}
progressDialog.setMessage("加載中");
progressDialog.show();
}
public void dismissLoading() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
二.搭建抽象類MvpActivity
package com.lcp.lcplibrary.mvp.view;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.lcp.lcplibrary.mvp.presenter.IBasePresenter;
/**
* Created by lcp on 2018/6/13.
*/
public abstract class MvpActivity<T, V extends IMvpView<T>, P extends IBasePresenter<V>> extends BasicActivity {
public P presenter;
private V view;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (presenter == null) {
presenter = createPresenter();
}
if (view == null) {
view = createView();
}
if (presenter != null && view != null) {
presenter.attachView(view);
}
if (presenter != null) {
presenter.onCreate();
}
//設定布局
setContentView(layoutId());
//加載本地資料
initData();
//初始化Ui
initView();
//加載網絡資料
initWeb();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.detachView();
presenter.onDestory();
}
}
protected abstract P createPresenter();
protected abstract V createView();
protected abstract int layoutId();
protected abstract void initView();
protected abstract void initWeb();
protected abstract void initData();
}
- 泛型的定義和BasePresenter相同
- 在onCreate方法裡實作初始化操作,建立抽象方法,在onCreate裡調用,讓子類重寫
- 在onDestroy裡釋放記憶體
五.Mvp架構的使用
以上是搭建mvp架構的過程,現在可以開始使用了
package com.lcp.lcplib.ui;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.lcp.lcplib.R;
import com.lcp.lcplib.service.manager.DataManager;
import com.lcp.lcplib.service.model.Book;
import com.lcp.lcplibrary.mvp.presenter.BasePresenter;
import com.lcp.lcplibrary.mvp.view.IMvpView;
import com.lcp.lcplibrary.mvp.view.MvpActivity;
import java.util.HashMap;
public class MainActivity extends MvpActivity<Book,IMvpView<Book>,BasePresenter<Book,IMvpView<Book>>> implements IMvpView<Book> {
private TextView text;
@Override
protected BasePresenter<Book, IMvpView<Book>> createPresenter() {
return new BasePresenter<>();
}
@Override
protected IMvpView<Book> createView() {
return this;
}
@Override
protected int layoutId() {
return R.layout.activity_main2;
}
@Override
protected void initView() {
text = (TextView) findViewById(R.id.text);
}
@Override
protected void initWeb() {
}
@Override
protected void initData() {
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
HashMap<String, Object> map = new HashMap<>();
map.put("q","金瓶梅");
map.put("tag","");
map.put("start",);
map.put("count",);
presenter.getData(DataManager.getInstance().getSearchbook(map));
}
});
}
@Override
public void onSuccess(Book book) {
text.setText(book.getBooks().get().getAlt_title());
}
@Override
public void onfailed(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
在你要實作Mvp架構的Activity裡,繼承MvpActivity,實作View的接口,傳入你想要的類型就可以實作了。
總結
- 以上就是自己搭建的mvp架構,我已經把相同的部分抽到一個庫裡,有需要的小夥伴直接使用即可
- 在MvpActivity搭建這塊泛型設計我覺得有些繁瑣,如果知道如何優化的大牛們歡迎私信我。
- 最後附上源碼https://github.com/laichangp/lcplib_覺得不錯的小夥伴可以點個星哈。