Retrofit+RxJava优雅的处理服务器
返
回异常、错误
异常&错误
实际开发经常有这种情况比如登录请求接口返回的信息包括请求返回的状态失败还是成功错误码 Us er对象等等。如果网络等原因引起的登录失败可以归结为异常如果是用户信息输入错误导致的登录失败算是错误。
假如服务器返回的是统一数据格式
*标准数据格式
*@p aram<T>
*/public class Response<T>{public int state;public String message;public T data;
}
网络异常导致的登录失败 在使用Retro fit+RxJava请求时都会直接调用s ub sc rib e的o nErro r事件密码错误导致的登录失败 在使用Retro fit+RxJava请求时都会调用s ub s c rib e的o nNext事件 无论是异常还是错误都要在subscribe里面处理异常信息如下代码
AP IWrapp er.getIns tanc e().lo g in("us ername", "p as s wo rd")
.subscribe(new Observer<Response<User>>() {@Override public void onCompleted() {
}
@Overrid epublic void onError(Throwable e) {
}
@Overrid epublic void onNext(Response<User>data) { if(data.state==1001){
//. . . . .
}els e if(data.state==1002){
});
现在我希望在发生任何错误的情况下都会调用o nErro r事件并且由mo d el来处理错误信息。那么此时我们就应该有一个Exc ep tio nEng ine来处理事件流中的错误信息了。
在工作流中处理异常
在正常情况下我们获取网络数据的流程通常如下
请求接口->解析数据->更新UI
整个数据请求过程都是发生在Rx中的工作流之中。当有异常产生的时候我们要尽量不在ui层里面进行判断换句话说我们没有必要去告诉ui层具体的错误信息只需要让他弹出一个信息(Toast或者Dialog)展示我们给它的信息就行。
请求接口和数据解析都可能出错所以在这两层进行错误处理。为了更好的解耦我们通过拦截器拦截错误然后根据错误类型分发信息。
拦截器
数据解析层的拦截器
这个拦截器主要是为了获取具体的错误信息分发给上层的UI 给用户以提示增强用户体验。public Observable<Weather>getWeather(String cityName){return weatherS ervic e.getWeather(c ityName)
//拦截服务器返回的错误
.map(new S erverRespons eFunc<Weather>())
//Http Res ultFunc()为拦截o nErro r事件的拦截器后面会讲到这里先忽略
.onErrorResumeNext(new HttpRespons eFunc<Weather>());
}
//拦截固定格式的公共数据类型 Respo nse<T>,判断里面的状态码private class ServerResponseFunc<T>imp lements Func 1<Response<T>,T>{
@Overrid epublic T call(Response<T>reponse) {
//对返回码进行判断如果不是 0则证明服务器端返回错误信息了便根据跟服务器约定好的错误码去解析异常if(rep o ns e.s tate !=0) {
统一处理throw new S erverExcepti on(repon se.state,rep on se.message);
}
//服务器请求数据成功返回里面的数据实体retur n repon se.data;
}
}
所以整个逻辑是这样的:
所以在前三步的过程中只要发生异常 服务器返回的错误也抛出了 都会抛出 这时候就触发了RxJava的O nErro r事件。
处理on Error事件的拦截器
这个拦截器主要是将异常信息转化为用户”能看懂”的友好提示。private class HttpResp on seF un c<T>impleme nts Fun c 1<Throwable,Observable<T>>{@Overridepublic Observable<T>call(Throwable throwab le) {
//Exc ep tio n Eng ine为处理异常的驱动器return Obs ervable.error(Exceptio nEn gi ne.ha nd leExc eptio n(throwable)); }
}
两个拦截器以前使用代码如下public Observable<Weather>getWeather(Stri ng cityName){return weatherS ervic e.getWeather(c ityName)
〃拦截服务器返回的错误
.map(new S erverResp on seF un c<Weather>())
//HttpRespo nseFu nc()为拦截on Error事件的拦截器.on ErrorResumeNext(new HttpResp ons eF un c<Weather>());
}
调用
AP IWrapp er.getIns tanc e().getWeather("北京")
.s ub s c rib e(new
S amp leP ro gres s Obs erver<Weathe r>(MainAc t iv ity.this) {
@Override public void onNext(WeatherBean weatherBean)
{ tv.s etT ext(weatherBean.to S tring());
}});
相关类public class RxSubscriber<T>extends ErrorSubscriber<T>{
@Overrid epublic void onStart() { super.onStart();DialogHelper.showProgressDlg(context, "正在加载数据");}
@Override public void onCompleted() {
D ialo gHe lp er.stop Pro gres s Dlg();
}
@Override protected void onError(ApiException ex) {
D ialo gH e lp er.s top Pro gres s Dlg();T o as t.makeT ext(c ontext,ex.mes s age,To as t.LENGTH_SHO RT).s how();}
@Overrid epublic void onNext(T t) {
}
}public abstract class ErrorSubscriber<T>extends Observer<T>{
@Overrid epublic void onError(Throwable e) { if(e instanceof ApiException){onError((Ap iException)e);
}els e{onError(new Ap iExc eption(e,123));
*错误回调
*/protected abstract void onError(ApiException ex); }
处理异常的驱动器p ac kage co m.s anniub en.n et;imp o rt andro id.net.P ars eExc ep tio n;imp ort com.google.gs on.Js onP ars eExc eption;imp ort org.js on.JS ONExc eption;imp o rt jav a.net.C o nnec tExc ep tio n;imp o rt retro fit2.adap ter.rxjav a.Http Exc ep t io n;
/**
*Created by Lzx on 2016/7/11.
*/public clas s ExceptionEngine {
//对应HT TP的状态码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_GA TEWAY=502;private static final int SERVICE_UNA VAILABLE=503;private static final int GATEW AY_TIMEOUT=504;public static ApiException handleException(Throwable e){
ApiException ex;if(e ins tanc eo f Http Exc ep tio n){ //HT T P错误Http Exc ep tio n http Exc ep tio n=(Http Exc ep tio n)e;ex=newAp iExc ep tion(e,ERRO R.HT TP_ERRO R); s witc h(http Exc ep tion.c ode()){c as e UNAUT HO RIZED:c as e F ORBIDDEN:case NOT_FOUND:
case REQUEST_TIMEOUT:c as e GAT EWAY_T IMEOUT:
c as e INTERNAL_S ERVER_ERROR:c as e BAD_GA TEWAY:
case SERVICE_UNA VAILABLE:default:
ex.mes s age="网络错误"; //均视为网络错误break;
}return ex;
} else if(e instanceof S erverException){ //服务器返回的错误
S erverExc ep t io n re s ultExc ep t io n=(S erverExc ep tio n)e;e x=new Ap iExc ep tio n(r e s ultExc ep tio n,re s ult Exc ep t io n.c od e);ex.me s s age=res ult Exc ep tio n.me s s age;return e x;
} else if(e instanceof JsonParseException
| |e instanc eo f JS ONExc eption
| |e instanc eo f P ars eExc eption){ex=new Ap iExc ep tio n(e,ERROR.P AR S E_ERRO R);ex.mes s age="解析错误";//均视为解析错误return ex;
}els e if(e instanc eof ConnectExc eption){ex=new Ap iExc ep tio n(e,ERROR.NETWO RD_ERRO R);ex.mes s age="连接失败"; //均视为网络错误return ex;
}els e {ex=new Ap iExc ep tio n(e,ERROR.UNKNO WN);ex.mes s age="未知错误";//未知错误return ex;
}
}
/**
约定异常
*/public 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 clas s ApiException extends Exception{public int code;public String mes sage;public ApiException(Throwab le throwable, int code) { super(throwable); this.code=code;
}
}public class ServerException extends RuntimeException{public int code;public String mes sage;
}
D ia lo gH e lp er.Javapublic class DialogHelper {
/**
*通用Dialog
*
*/
//因为本类不是activity所以通过继承接口的方法获取到点击的事件public interfac e OnOkClickListener{abstract void onOkClick();
*L is tener
*/public interface OnCancelC lickListener {abstract void onCancelClick();
}private static AlertDialog mDialog;public static void showDialog(Context context,String title,String content,final OnOkClickListener listenerYes,fina l O nC anc e lC lic kL is te ner lis ten erNo) {s ho wDialo g(c o ntext,c o ntext.getS tring(andro id.R.s tring.o k),context.getS tring(andro id.R.s tring.c anc el),tit le,c ontent, lis tene rYes, lis te nerNo);
}public static void showDialog(Context context,String ok,String c ancel,String title,String content,finalOnOkC lic kL is tener lis ten erY es,final OnC anc e lC lickListener listenerNo) {AlertDialo g.Builderbuilder=new AlertD ialo g.Builder(c ontext);builder.s etMes s age(c ontent);
//设置title builder.setTitle(title);
//设置确定按钮 固定用法声明一个按钮用这个setPositiveButton builder.setPositiveButton(ok,new D ialo gInt erfac e.OnC lic kL is te ner() {public void onClick(DialogInterface dialog, int which) {
//如果确定被电击if(lis tene rYes !=null) { lis tenerYes.onOkC lic k();
}mDialog=null;
}});
//设置取消按钮 固定用法声明第二个按钮要用s etNegativeButton builder.s etNegativeButton(c anc e l,new D ialo gInt erfac e.OnC lic kL is te ner() {public void onClick(DialogInterface dialog, int which) {
//如果取消被点击if(lis tenerNo !=null) { lis tenerNo.onC anc elC lic k();
}mDialog=null;
});
//控制这个dialo g可不可以按返回键 true为可以 fals e为不可以b uild er.s etC anc elab le(fa ls e);
//显示dialogmD ialo g=builder.create();if(!mD ia lo g.is S ho wing())mDialog.show();
}public static void showDialog(Context context, int ok, int cancel, int title, int content,final OnOkClickListenerlis ten erY es,final OnC anc e lC lic kL is tener lis tenerNo) { s howDialo g(c ontext,c ontext.getS tring(ok),c ontext.getS tring(c anc e l),c ontext.getS tring(title),c ontext.getS tring(c ontent), lis tenerYes,lis ten erNo);
}static ProgressDialog progressDlg=null;
/**
*启动进度条
*
*@param strMessage进度条显示的信息
*@p aram//当前的ac tiv ity
*/public static void showProgressDlg(Context ctx,String strMessage) {if(null==pro gress Dlg) {if(c tx==null)return;progressDlg=new Progres sDialog(ctx);
//设置进度条样式p ro gress Dlg.s etP ro gres s S tyle(P ro gres s Dialo g.S TYLE_SP INNER);
//提示的消息progressDlg.s etMes s age(strMes s age);p ro gre s s Dlg.s etInd ete rminate(fa ls e);pro gress Dlg.s etC anc e lab le(true);p ro gre s s Dlg.s ho w();
}
}public static void showProgressDlg(Context ctx) { showProgressDlg(ctx, "");
*结束进度条
*/public static void stopProgressDlg() {if(null !=progres sDlg&&progres sDlg.is Showing()) {p ro gress Dlg.dis mis s();
提速啦的来历提速啦是 网站 本着“良心 便宜 稳定”的初衷 为小白用户避免被坑 由赣州王成璟网络科技有限公司旗下赣州提速啦网络科技有限公司运营 投资1000万人民币 在美国Cera 香港CTG 香港Cera 国内 杭州 宿迁 浙江 赣州 南昌 大连 辽宁 扬州 等地区建立数据中心 正规持有IDC ISP CDN 云牌照 公司。公司购买产品支持3天内退款 超过3天步退款政策。提速啦的市场定位提速啦主...
npidc全称No Problem Network Co.,Limited(冇問題(香港)科技有限公司,今年4月注册的)正在搞云服务器和独立服务器促销,数据中心有香港、美国、韩国,走CN2+BGP线路无视高峰堵塞,而且不限制流量,支持自定义内存、CPU、硬盘、带宽等,采用金盾+天机+傲盾防御系统拦截CC攻击,非常适合建站等用途。活动链接:https://www.npidc.com/act.html...
百纵科技怎么样?百纵科技国人商家,ISP ICP 电信增值许可证的正规公司,近期上线美国C3机房洛杉矶独立服务器,大带宽/高配置多ip站群服务器。百纵科技拥有专业技术售后团队,机器支持自动化,自助安装系统 重启,开机交付时间 30分钟内交付!美国洛杉矶高防服务器配置特点: 硬件配置高 线路稳定 洛杉矶C3机房等级T4 平价销售,支持免费测试,美国独服适合做站,满意付款。点击进入:百纵科技官方网站地...