错误retrofit rxjava优雅的处理服务器返回异常、错误

服务器连接异常  时间:2021-02-09  阅读:()

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();

RAKsmart秒杀服务器$30/月,洛杉矶/圣何塞/香港/日本站群特价

RAKsmart发布了9月份优惠促销活动,从9月1日~9月30日期间,爆款美国服务器每日限量抢购最低$30.62-$46/月起,洛杉矶/圣何塞/香港/日本站群大量补货特价销售,美国1-10Gbps大带宽不限流量服务器低价热卖等。RAKsmart是一家华人运营的国外主机商,提供的产品包括独立服务器租用和VPS等,可选数据中心包括美国加州圣何塞、洛杉矶、中国香港、韩国、日本、荷兰等国家和地区数据中心(...

HostYun(22元/月)全场88折优惠香港原生IP大带宽

在之前的一些文章中有提到HostYun商家的信息,这个商家源头是比较老的,这两年有更换新的品牌域名。在陆续的有新增机房,价格上还是走的低价格路线,所以平时的折扣力度已经是比较低的。在前面我也有介绍到提供九折优惠,这个品牌商家就是走的低价量大为主。中秋节即将到,商家也有推出稍微更低的88折。全场88折优惠码:moon88这里,整理部分HostYun商家的套餐。所有的价格目前都是原价,我们需要用折扣码...

捷锐数据399/年、60元/季 ,香港CN2云服务器 4H4G10M

捷锐数据官网商家介绍捷锐数据怎么样?捷锐数据好不好?捷锐数据是成立于2018年一家国人IDC商家,早期其主营虚拟主机CDN,现在主要有香港云服、国内物理机、腾讯轻量云代理、阿里轻量云代理,自营香港为CN2+BGP线路,采用KVM虚拟化而且单IP提供10G流量清洗并且免费配备天机盾可达到屏蔽UDP以及无视CC效果。这次捷锐数据给大家带来的活动是香港云促销,总共放量40台点击进入捷锐数据官网优惠活动内...

服务器连接异常为你推荐
google地球打不开谷歌地球现在为什么打不开了赛我网赛我网(cyworld)怎么进不去?51自学网站谁能给我免费学习的网站吧 谢谢了人人时光机现在世界上有时光机吗arm开发板ARM开发板具体有什么作用?有什么商业价值?申请证书申请毕业证书ejb开发EJB是啥玩意了bt封杀现在是全面封杀BT下载了吗?现在都找不到BT下载影片了小米手柄小米蓝牙游戏手柄怎么连接游戏srv记录如何验证是否为域控制器创建了 SRV DNS 记录
查询ip 免费网站空间 淘宝虚拟主机 根域名服务器 如何申请免费域名 骨干网 老左 virpus 电影服务器 uk2 91vps 卡巴斯基试用版 佛山高防服务器 cn3 河南移动m值兑换 购买空间 广东主机托管 网络速度 塔式服务器 restart 更多