Retrofit RxJava优雅的处理服务器返回异常错误分解.docx
《Retrofit RxJava优雅的处理服务器返回异常错误分解.docx》由会员分享,可在线阅读,更多相关《Retrofit RxJava优雅的处理服务器返回异常错误分解.docx(19页珍藏版)》请在冰豆网上搜索。
RetrofitRxJava优雅的处理服务器返回异常错误分解
Retrofit+RxJava优雅的处理服务器返回异常、错误
异常&错误
实际开发经常有这种情况,比如登录请求,接口返回的
信息包括请求返回的状态:
失败还是成功,错误码,User对象等等。
如果网络等原因引起的登录失败可以归结为异常,如果是用户信息输入错误导致的登录失败算是错误。
假如服务器返回的是统一数据格式:
/**
*标准数据格式
*@param
*/
publicclassResponse{
publicintstate;
publicStringmessage;
publicTdata;
}
网络异常导致的登录失败,在使用Retrofit+RxJava请求时都会直接调用subscribe的onError事件;
密码错误导致的登录失败,在使用Retrofit+RxJava请求时都会调用subscribe的onNext事件;
无论是异常还是错误,都要在subscribe里面处理异常信息,如下代码:
APIWrapper.getInstance().login("username","password")
.subscribe(newObserver>(){
@Override
publicvoidonCompleted(){
}
@Override
publicvoidonError(Throwablee){
}
@Override
publicvoidonNext(Responsedata){
if(data.state==1001){
//.....
}elseif(data.state==1002){
}
}
});
现在我希望在发生任何错误的情况下,都会调用onError事件,并且由model来处理错误信息。
那么,此时我们就应该有一个ExceptionEngine来处理事件流中的错误信息了。
在工作流中处理异常
在正常情况下,我们获取网络数据的流程通常如下:
请求接口->解析数据->更新UI
整个数据请求过程都是发生在Rx中的工作流之中。
当有异常产生的时候,我们要尽量不在ui层里面进行判断,换句话说,我们没有必要去告诉ui层具体的错误信息,只需要让他弹出一个信息(Toast或者Dialog)展示我们给它的信息就行。
请求接口和数据解析都可能出错,所以在这两层进行错误处理。
为了更好的解耦,我们通过拦截器拦截错误,然后根据错误类型分发信息。
拦截器
数据解析层的拦截器
这个拦截器主要是为了获取具体的错误信息,分发给上层的UI,给用户以提示,增强用户体验。
publicObservablegetWeather(StringcityName){
returnweatherService.getWeather(cityName)
//拦截服务器返回的错误
.map(newServerResponseFunc())
//HttpResultFunc()为拦截onError事件的拦截器,后面会讲到,这里先忽略
.onErrorResumeNext(newHttpResponseFunc());
}
//拦截固定格式的公共数据类型Response,判断里面的状态码
privateclassServerResponseFuncimplementsFunc1,T>{
@Override
publicTcall(Responsereponse){
//对返回码进行判断,如果不是0,则证明服务器端返回错误信息了,便根据跟服务器约定好的错误码去解析异常
if(reponse.state!
=0){
//如果服务器端有错误信息返回,那么抛出异常,让下面的方法去捕获异常做统一处理
thrownewServerException(reponse.state,reponse.message);
}
//服务器请求数据成功,返回里面的数据实体
returnreponse.data;
}
}
所以整个逻辑是这样的:
所以在前三步的过程中,只要发生异常(服务器返回的错误也抛出了)都会抛出,这时候就触发了RxJava的OnError事件。
处理onError事件的拦截器
这个拦截器主要是将异常信息转化为用户”能看懂”的友好提示。
privateclassHttpResponseFuncimplementsFunc1>{
@Override
publicObservablecall(Throwablethrowable){
//ExceptionEngine为处理异常的驱动器
returnObservable.error(ExceptionEngine.handleException(throwable));
}
}
两个拦截器以前使用,代码如下:
publicObservablegetWeather(StringcityName){
returnweatherService.getWeather(cityName)
//拦截服务器返回的错误
.map(newServerResponseFunc())
//HttpResponseFunc()为拦截onError事件的拦截器
.onErrorResumeNext(newHttpResponseFunc());
}
调用:
APIWrapper.getInstance().getWeather("北京")
.subscribe(newSampleProgressObserver(MainActivity.this){
@Override
publicvoidonNext(WeatherBeanweatherBean){
tv.setText(weatherBean.toString());
}
});
相关类:
publicclassRxSubscriberextendsErrorSubscriber{
@Override
publicvoidonStart(){
super.onStart();
DialogHelper.showProgressDlg(context,"正在加载数据");
}
@Override
publicvoidonCompleted(){
DialogHelper.stopProgressDlg();
}
@Override
protectedvoidonError(ApiExceptionex){
DialogHelper.stopProgressDlg();
Toast.makeText(context,ex.message,Toast.LENGTH_SHORT).show();
}
@Override
publicvoidonNext(Tt){
}
}
publicabstractclassErrorSubscriberextendsObserver{
@Override
publicvoidonError(Throwablee){
if(einstanceofApiException){
onError((ApiException)e);
}else{
onError(newApiException(e,123));
}
}
/**
*错误回调
*/
protectedabstractvoidonError(ApiExceptionex);
}
处理异常的驱动器
package;
import.ParseException;
importcom.google.gson.JsonParseException;
importorg.json.JSONException;
import.ConnectException;
importretrofit2.adapter.rxjava.HttpException;
/**
*CreatedbyLzxon2016/7/11.
*/
publicclassExceptionEngine{
//对应HTTP的状态码
privatestaticfinalintUNAUTHORIZED=401;
privatestaticfinalintFORBIDDEN=403;
privatestaticfinalintNOT_FOUND=404;
privatestaticfinalintREQUEST_TIMEOUT=408;
privatestaticfinalintINTERNAL_SERVER_ERROR=500;
privatestaticfinalintBAD_GATEWAY=502;
privatestaticfinalintSERVICE_UNAVAILABLE=503;
privatestaticfinalintGATEWAY_TIMEOUT=504;
publicstaticApiExceptionhandleException(Throwablee){
ApiExceptionex;
if(einstanceofHttpException){//HTTP错误
HttpExceptionhttpException=(HttpException)e;
ex=newApiException(e,ERROR.HTTP_ERROR);
switch(httpException.code()){
caseUNAUTHORIZED:
caseFORBIDDEN:
caseNOT_FOUND:
caseREQUEST_TIMEOUT:
caseGATEWAY_TIMEOUT:
caseINTERNAL_SERVER_ERROR:
caseBAD_GATEWAY:
caseSERVICE_UNAVAILABLE:
default:
ex.message="网络错误";//均视为网络错误
break;
}
returnex;
}elseif(einstanceofServerException){//服务器返回的错误
ServerExceptionresultException=(ServerException)e;
ex=newApiException(resultException,resultException.code);
ex.message=resultException.message;
returnex;
}elseif(einstanceofJsonParseException
||einstanceofJSONException
||einstanceofParseException){
ex=newApiException(e,ERROR.PARSE_ERROR);
ex.message="解析错误";//均视为解析错误
returnex;
}elseif(einstanceofConnectException){
ex=newApiException(e,ERROR.NETWORD_ERROR);
ex.message="连接失败";//均视为网络错误
returnex;
}else{
ex=newApiException(e,ERROR.UNKNOWN);
ex.message="未知错误";//未知错误
returnex;
}
}
}
/**
*约定异常
*/
publicclassERROR{
/**
*未知错误
*/
publicstaticfinalintUNKNOWN=1000;
/**
*解析错误
*/
publicstaticfinalintPARSE_ERROR=1001;
/**
*网络错误
*/
publicstaticfinalintNETWORD_ERROR=1002;
/**
*协议出错
*/
publicstaticfinalintHTTP_ERROR=1003;
}
publicclassApiExceptionextendsException{
publicintcode;
publicStringmessage;
publicApiException(Throwablethrowable,intcode){
super(throwable);
this.code=code;
}
}
publicclassServerExceptionextendsRuntimeException{
publicintcode;
publicStringmessage;
}
DialogHelper.Java
publicclassDialogHelper{
/**
*通用Dialog
*
*/
//因为本类不是activity所以通过继承接口的方法获取到点击的事件
publicinterfaceOnOkClickListener{
abstractvoidonOkClick();
}
/**
*Listener
*/
publicinterfaceOnCancelClickListener{
abstractvoidonCancelClick();
}
privatestaticAlertDialogmDialog;
publicstaticvoidshowDialog(Contextcontext,Stringtitle,Stringcontent,finalOnOkClickListenerlistenerYes,
finalOnCancelClickListenerlistenerNo){
showDialog(context,context.getString(android.R.string.ok),context.getString(android.R.string.cancel),title,content,listenerYes,listenerNo);
}
publicstaticvoidshowDialog(Contextcontext,Stringok,Stringcancel,Stringtitle,Stringcontent,finalOnOkClickListenerlistenerYes,
finalOnCancelClickListenerlistenerNo){
AlertDialog.Builderbuilder=newAlertDialog.Builder(context);
builder.setMessage(content);
//设置title
builder.setTitle(title);
//设置确定按钮,固定用法声明一个按钮用这个setPositiveButton
builder.setPositiveButton(ok,
newDialogInterface.OnClickListener(){
publicvoidonClick(DialogInterfacedialog,intwhich){
//如果确定被电击
if(listenerYes!
=null){
listenerYes.onOkClick();
}
mDialog=null;
}
});
//设置取消按钮,固定用法声明第二个按钮要用setNegativeButton
builder.setNegativeButton(cancel,
newDialogInterface.OnClickListener(){
publicvoidonClick(DialogInterfacedialog,intwhich){
//如果取消被点击
if(listenerNo!
=null){
listenerNo.onCancelClick();
}
mDialog=null;
}
});
//控制这个dialog可不可以按返回键,true为可以,false为不可以
builder.setCancelable(false);
//显示dialog
mDialog=builder.create();
if(!
mDialog.isShowing())
mDialog.show();
}
publicstaticvoidshowDialog(Contextcontext,intok,intcancel,inttitle,intcontent,finalOnOkClickListenerlistenerYes,
finalOnCancelClickListenerlistenerNo){
showDialog(context,context.getString(ok),context.getString(cancel),context.getString(title),context.getString(content),listenerYes,listenerNo);
}
staticProgressDialogprogressDlg=null;
/**
*启动进度条
*
*@paramstrMessage进度条显示的信息
*@param//当前的activity
*/
publicstaticvoidshowProgressDlg(Contextctx,StringstrMessage){
if(null==progressDlg){
if(ctx==null)return;
progressDlg=newProgressDialog(ctx);
//设置进度条样式
progressDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//提示的消息
progressDlg.setMessage(strMessage);
progressDlg.setIndeterminate(false);
progressDlg.setCancelable(true);
progressDlg.show();
}
}
publicstaticvoidshowProgressDlg(Contextctx){
showProgressDlg(ctx,"");
}
/**
*结束进度条
*/
publicstaticvoidstopProgressDlg(){
if(null!
=progressDlg&&progressDlg.isShowing()){
progressDlg.dismiss();
progressDlg=null;
}
if(null!
=dialog&&dialog.isShowing()){
dialog.dismiss();
dialog=null;
}
}
privatestaticDialogdialog;
publicstaticvoidshowDialogForLoading(Contextcontext,Stringmsg,booleancancelable){
if(null==dialog){
if(null==context)return;
Viewview=LayoutInflater.from(context).inflate(R.layout.layout_loading_dialog,null);
TextViewloadingText=(TextView)view.findViewById(R.id.loading_tip_text);
loadingText.setText(msg);
dialog=newDialog(context,R.style.loading_dialog_style);
dialog.setCancelable(cancelable);
dialog.setCanceledOnTouchOutside(cancelable);
dialog.setContentView(iew,newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
Activityactivity=(Activity)context;
if(activity.isFinishing())return;
dialog.show();
}
}
}
可能本博客也不是最好的解决方案,如果有更好的想法,我愿与你互相交流!
分享:
Retrofit+RxJava错误预处理
看到bobo_wang的文章,不仅感觉有受益匪浅,这里做下介绍。
首先定义如下Transformer转换器。
publicstaticObservable.Transformer,T>sTransformer(){
returnresponseObservable->responseObservable.map(tResponse->{
if(!
tResponse.success)thrownewRuntimeExcept