9102年了,终于准备用mvp来重构一下了
之前写过Mvc模式下的Retrofit统一异常处理,这次用MVP重构过程中发现诸多不足之处,便重新进行修缮,使其在我看来更加优雅emmmmmm,文中不足之处,还望诸位同仁多多指点。
BaseView
BaseView接口定义了可能用到的方法,特别是 addSubscribe
,用来管理RxJava生命周期。
public interface BaseView { /** * 显示吐司 * * @param msg 提示消息 */ void showMsg(String msg); /** * 显示加载动画 */ void showProgress(); /** * 显示提示 */ void showTip(@QMUITipDialog.Builder.IconType int iconType, CharSequence tipWord); /** * 关闭加载动画 */ void hideProgress(); /** * 关闭提示 */ void hideTip(); /** * 跳转页面 */ void startActivitySample(Class<?> cls); /** * Rx事件管理 * * @param subscription */ void addSubscribe(Disposable subscription); } 复制代码
BasePresenter
BasePresenter方法中只定义了绑定View与解绑View的接口
public interface BasePresenter<T extends BaseView> { void attachView(T view); void detachView(); } 复制代码
BaseActivity/Fragment
这个类是封装了一些常用方法,并且实现了BaseView的全部接口。 并且预留了两个用于mvp模式的空方法
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); initContentView(R.layout.activity_base); setContentView(getLayout()); mTopBar = (QMUITopBar) findViewById(R.id.base_topbar); ButterKnife.bind(this); mContext = this; mSwipeBackLayout = getSwipeBackLayout(); if (isStartSwipeBack()) { mSwipeBackLayout.setEdgeTrackingEnabled(SwipeBackLayout.EDGE_LEFT); } else { mSwipeBackLayout.setEnableGesture(false); } AppManager.addActivity(this); // 在此处调用绑定Presenter方法 initPresenter(); initEventAndData(); } @Override protected void onDestroy() { unSubscribe(); removePresenter(); AppManager.removeActivity(this); super.onDestroy(); } protected void initPresenter() { } protected void removePresenter() { } 复制代码
BaseMvpActivity/Fragment
实现了base中的预留方法
public abstract class BaseMvpActivity<T extends BasePresenter> extends BaseActivity { protected T mPresenter; @Override protected void initPresenter() { mPresenter = createPresenter(); if (mPresenter != null) { mPresenter.attachView(this); } } @Override protected void removePresenter() { if (mPresenter != null) { mPresenter.detachView(); } } /** * 创建Presenter * * @return */ protected abstract T createPresenter(); } 复制代码
SamplePresenter
SamplePresenter实现了BasePresenter中的绑定view与解绑view
BaseResponse
RESTful API的基类,看下代码很容易明白,但是需要注意下 isOk(BaseView view)
方法
public class BaseResponse<T> { private int statusCode; private String message; private T data; public boolean isOk(BaseView view) { // statusCode == 1服务器请求成功 if (statusCode == 1) { return true; } else { // 服务器正常请求返回的错误 NetworkError.error(view, new ServerException(statusCode, message)); return false; } } // get/set... } 复制代码
NetworkError
根据不同的标志统一处理异常以及服务器返回的错误
public class NetworkError { public static void error(BaseView view, Throwable throwable) { RetrofitException.ResponeThrowable responeThrowable = RetrofitException.retrofitException(throwable); // 此处可以通过判断错误代码来实现根据不同的错误代码做出相应的反应 switch (responeThrowable.code) { case RetrofitException.ERROR.UNKNOWN: case RetrofitException.ERROR.PARSE_ERROR: case RetrofitException.ERROR.NETWORD_ERROR: case RetrofitException.ERROR.HTTP_ERROR: case RetrofitException.ERROR.SSL_ERROR: view.showMsg(responeThrowable.message); break; case -1: // 跳转到登陆页面 view.startActivitySample(LoginActivity.class); break; default: view.showMsg(responeThrowable.message); break; } } } 复制代码
ServerException
自定义服务器异常
public class ServerException extends RuntimeException { public int code; public ServerException(int code, String message) { super(message); this.code = code; } } 复制代码
RetrofitException
自定义网络异常,获取错误原因
public class RetrofitException { private static final int UNAUTHORIZED = 401; private static final int FORBIDDEN = 403; private static final int NOT_FOUND = 404; private static final int REQUEST_TIMEOUT = 408; private static final int INTERNAL_SERVER_ERROR = 500; private static final int BAD_GATEWAY = 502; private static final int SERVICE_UNAVAILABLE = 503; private static final int GATEWAY_TIMEOUT = 504; public static ResponeThrowable retrofitException(Throwable e) { ResponeThrowable ex; if (e instanceof HttpException) { HttpException httpException = (HttpException) e; ex = new ResponeThrowable(e, ERROR.HTTP_ERROR); switch (httpException.code()) { case UNAUTHORIZED: case FORBIDDEN: case NOT_FOUND: case REQUEST_TIMEOUT: case GATEWAY_TIMEOUT: case INTERNAL_SERVER_ERROR: case BAD_GATEWAY: case SERVICE_UNAVAILABLE: default: ex.message = "网络错误"; break; } return ex; } else if (e instanceof ServerException) { // 服务器下发的错误 ServerException resultException = (ServerException) e; ex = new ResponeThrowable(resultException, resultException.code); ex.message = resultException.getMessage(); 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 || e instanceof SocketTimeoutException || e instanceof UnknownHostException) { ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR); ex.message = "连接失败"; return ex; } else if (e instanceof SSLHandshakeException) { ex = new ResponeThrowable(e, ERROR.SSL_ERROR); ex.message = "证书验证失败"; return ex; } else { ex = new ResponeThrowable(e, ERROR.UNKNOWN); ex.message = "未知错误"; return ex; } } /** * 约定异常 */ class ERROR { /** * 未知错误 */ public static final int UNKNOWN = 1000; /** * 解析错误 */ public static final int PARSE_ERROR = 1001; /** * 网络错误 */ public static final int NETWORD_ERROR = 1002; /** * 协议出错 */ public static final int HTTP_ERROR = 1003; /** * 证书出错 */ public static final int SSL_ERROR = 1005; } public static class ResponeThrowable extends Exception { public int code; public String message; public ResponeThrowable(Throwable throwable, int code) { super(throwable); this.code = code; } } } 复制代码
RetrofitClient
使用单例封装的Retrofit,这里就不写了,相信大家都写过
ServiceApi
这个是Api接口与 11
对应,这里用的 Observable
,感觉没必要用 Flowable
,用 Flowable
的话下面 12
这个就不是这么写了
public interface ServiceApi { /** * 测试接口 */ @POST("test") Observable<BaseResponse<LoginModel>> login(); } 复制代码
RetrofitSubscriber(Observer)
通过 BaseView
调用在BaseActivity/Fragment中实现的 addSubscribe
将 Disposable
添加到 CompositeDisposable
中,在页面销毁时先中断请求,以免造成view销毁了还去调用导致空指针异常。并且根据 Observer
的接口通过 BaseView
来处理加载动画(在BaseActivity/Fragment中实现)。
public abstract class RetrofitSubscriber<T> implements Observer<T> { private final WeakReference<BaseView> mView; public RetrofitSubscriber(BaseView view) { super(); mView = new WeakReference<>(view); } @Override public void onSubscribe(Disposable d) { if (!NetworkUtils.isConnected()) { mView.get().showMsg("网络未连接,请检查网络"); d.dispose(); } else { mView.get().showProgress(); mView.get().addSubscribe(d); } } @Override public void onComplete() { if (mView != null && mView.get() != null) { mView.get().hideProgress(); } } @Override public void onError(Throwable e) { if (mView != null && mView.get() != null) { mView.get().hideProgress(); } onNetError(e); } @Override public void onNext(T response) { if (response instanceof BaseResponse) { if (((BaseResponse) response).isOk(mView.get())) { onSuccess(response); } else { onServiceError(response); } } else { onOtherSuccess(response); } } /** * 请求成功并且服务器未下发异常 * * @param response */ protected abstract void onSuccess(T response); /** * 请求成功, 返回非继承自BaseResponse的非标准Bean或字符串 * * @param response */ protected void onOtherSuccess(T response) { } /** * 请求成功,服务器下发异常 * * @param response */ protected void onServiceError(T response) { } /** * 网络异常 * * @param e */ protected void onNetError(Throwable e) { if (mView != null && mView.get() != null) { NetworkError.error(mView.get(), e); } } } 复制代码
放一张我画的流程图,比较魔性
Contract
public interface LoginContract { interface View extends BaseView { /** * 登陆成功 * @param loginModel */ void loginSuccess(LoginModel loginModel); } interface Presenter extends BasePresenter<View> { /** * 登陆 */ void login(String userName, String pwd); } } 复制代码
Activity
public class LoginActivity extends BaseMvpActivity<LoginPresenter> implements LoginContract.View { @BindView(R.id.et_login_user) ClearEditText mEtLoginUser; @BindView(R.id.et_login_password) ClearEditText mEtLoginPassword; @Override protected int getLayout() { return R.layout.activity_login; } @Override protected void initEventAndData() { initView(); } @Override protected LoginPresenter createPresenter() { return new LoginPresenter(); } private void initView() { // ... } private void toLogin() { mPresenter.login(mEtLoginUser.getText().toString(), mEtLoginPassword.getText().toString(); } @Override public void loginSuccess(LoginModel loginModel) { startActivity(new Intent(mContext, MainActivity.class)); finish(); } @OnClick({R.id.tv_login_submit}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.tv_login_submit: //上传用户名和密码的方法 login(); break; } } } 复制代码
Presenter
public class LoginPresenter extends SamplePresenter<LoginContract.View> implements LoginContract.Presenter { @Override public void login(String userName, String pwd) { RetrofitClient .getInstance() .gService .login() .compose(RxSchedulersUtils.rxObservableSchedulerHelper()) .subscribe(new RetrofitSubscriber<BaseResponse<LoginModel>>(mView) { @Override protected void onSuccess(BaseResponse<LoginModel> response) { mView.loginSuccess(response.getData()); } }); } } 复制代码