《RetrofitRxJava优雅的处理服务器返回异常、错误分解》由会员分享,可在线阅读,更多相关《RetrofitRxJava优雅的处理服务器返回异常、错误分解(13页珍藏版)》请在人人文库网上搜索。
1、Retrofit+RxJava 优雅的处理服务器返回异常、错误异常 &错误实际开发经常有这种情况,比如登录请求,接口返回的 信息包括请求返回的状态:失败还是成功,错误码, User 对象等等。如果网络等原因引起 的登录失败可以归结为异常,如果是用户信息输入错误导致的登录失败算是错误。假如服务器返回的是统一数据格式:* 标准数据格式* param */public class Response public int state;public String message; public T data;网络异常导致的登录失败, 在使用 Retrofit+RxJava 请求时都会直接调用 subsc。
2、ribe 的 onError 事件;密码错误导致的登录失败, 在使用 Retrofit+RxJava 请求时都会调用 subscribe 的 onNext 事件; 无论是异常还是错误,都要在 subscribe 里面处理异常信息,如下代码:APIWrapper.getInstance().login(username, password).subscribe(new Observer() Override public void onCompleted() Overridepublic void onError(Throwable e) Overridepublic void onNext(R。
3、esponse data) if(data.state = 1001)/else if(data.state = 1002);现在我希望在发生任何错误的情况下,都会调用 onError 事件,并且由 model 来处理错误信 息。那么,此时我们就应该有一个 ExceptionEngine 来处理事件流中的错误信息了。在工作流中处理异常在正常情况下,我们获取网络数据的流程通常如下:请求接口 -解析数据- 更新UI整个数据请求过程都是发生在 Rx 中的工作流之中。当有异常产生的时候,我们要尽量不在 ui 层里面进行判断,换句话说,我们没有必要去告诉 ui 层具体的错误信息,只需要让他弹 出一个信息。
4、( Toast 或者 Dialog )展示我们给它的信息就行。请求接口和数据解析都可能出错, 所以在这两层进行错误处理。 为了更好的解耦, 我们通过 拦截器拦截错误,然后根据错误类型分发信息。拦截器数据解析层的拦截器这个拦截器主要是为了获取具体的错误信息,分发给上层的 UI ,给用户以提示,增强用户 体验。public Observable getWeather(String cityName)return weatherService.getWeather(cityName)/拦截服务器返回的错误.map(new ServerResponseFunc()/HttpResultFunc ()为。
5、拦截 onError 事件的拦截器,后面会讲到,这里先 忽略.onErrorResumeNext(new HttpResponseFunc();/拦截固定格式的公共数据类型Respo nse,判断里面的状态码private class ServerResponseFunc implements Func1, T Overridepublic T call(Response reponse) /对返回码进行判断,如果不是0,则证明服务器端返回错误信息了,便根据跟服务器约定好的错误码去解析异常if (reponse.state != 0) 统一处理throw new ServerExcepti o。
6、n(repon se.state,rep on se.message);/服务器请求数据成功,返回里面的数据实体retur n repon se.data;所以整个逻辑是这样的:所以在前三步的过程中,只要发生异常(服务器返回的错误也抛出了)都会抛出,这时候就触发了 RxJava 的 OnError 事件。处理on Error事件的拦截器这个拦截器主要是将异常信息转化为用户”能看懂”的友好提示。private class HttpResp on seF un c impleme nts Fun c1 Overridepublic Observable call(Throwable throwab。
7、le) /ExceptionEngine为处理异常的驱动器return Observable.error(Exceptio nEn gi ne.ha ndleExceptio n(throwable); 两个拦截器以前使用,代码如下:public Observable getWeather(Stri ng cityName)return weatherService.getWeather(cityName)拦截服务器返回的错误.map( new ServerResp on seF un c()/HttpRespo nseFu nc ()为拦截on Error事件的拦截器 .on ErrorRe。
8、sumeNext (new HttpResp on seF un c();调用:APIWrapper.getInstance().getWeather(北京).subscribe( newSampleProgressObserver(MainActivity.this) Override public void onNext(WeatherBean weatherBean) tv.setText(weatherBean.toString(); );相关类:public class RxSubscriber extends ErrorSubscriber Overridepublic void 。
9、onStart() super.onStart(); DialogHelper.showProgressDlg(context, 正在加载数据 );Override public void onCompleted() DialogHelper.stopProgressDlg();Override protected void onError(ApiException ex) DialogHelper.stopProgressDlg(); Toast.makeText(context, ex.message, Toast.LENGTH_SHORT).show();Overridepublic v。
10、oid onNext(T t) public abstract class ErrorSubscriber extends Observer Overridepublic void onError(Throwable e) if(e instanceof ApiException) onError(ApiException)e);else onError(new ApiException(e,123);* 错误回调*/protected abstract void onError(ApiException ex); 处理异常的驱动器package ;import .ParseException。
11、;import com.google.gson.JsonParseException;import org.json.JSONException;import .ConnectException;import retrofit2.adapter.rxjava.HttpException;/* Created by Lzx on 2016/7/11.*/public class ExceptionEngine /对应 HTTP 的状态码private static final int UNAUTHORIZED = 401;private static final int FORBIDDEN = 。
12、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 stat。
13、ic ApiException handleException(Throwable e)ApiException ex;if (e instanceof HttpException) /HTTP 错误 HttpException httpException = (HttpException) e; ex = new ApiException(e, ERROR.HTTP_ERROR); switch(httpException.code()case UNAUTHORIZED:case FORBIDDEN:case NOT_FOUND:case REQUEST_TIMEOUT:case GATEW。
14、AY_TIMEOUT:case INTERNAL_SERVER_ERROR: case BAD_GA TEWAY:case SERVICE_UNA VAILABLE: default:ex.message = 网络错误 ; / 均视为网络错误 break;return ex; else if (e instanceof ServerException)/ 服务器返回的错误ServerException resultException = (ServerException) e; ex = new ApiException(resultException, resultException.cod。
15、e); ex.message = resultException.message; return ex; else if (e instanceof JsonParseException| e instanceof JSONException| e instanceof ParseException)ex = new ApiException(e, ERROR.PARSE_ERROR); ex.message = 解析错误 ;/均视为解析错误return ex;else if(e instanceof ConnectException)ex = new ApiException(e, ERRO。
16、R.NETWORD_ERROR); ex.message = 连接失败 ; /均视为网络错误 return ex;else ex = new ApiException(e, ERROR.UNKNOWN); ex.message = 未知错误 ;/ 未知错误return ex;/*约定异常*/public class ERROR /* 未知错误*/public static final int UNKNOWN = 1000; /* 解析错误*/public static final int PARSE_ERROR = 1001;/* 网络错误*/public static final int N。
17、ETWORD_ERROR = 1002; /* 协议出错*/public static final int HTTP_ERROR = 1003;public class ApiException extends Exception public int code;public String message;public ApiException(Throwable throwable, int code) super(throwable); this.code = code;public class ServerException extends RuntimeException public。
18、 int code;public String message;DialogHelper.Javapublic class DialogHelper /* 通用 Dialog*/ 因为本类不是 activity 所以通过继承接口的方法获取到点击的事件 public interface OnOkClickListener abstract void onOkClick();* Listener*/public interface OnCancelClickListener abstract void onCancelClick();private static AlertDialog mDial。
19、og;public static void showDialog(Context context, String title, String content, final OnOkClickListener listenerYes,final OnCancelClickListener listenerNo) showDialog(context, context.getString(android.R.string.ok), context.getString(android.R.string.cancel), title, content, listenerYes, listenerNo)。
20、;public static void showDialog(Context context, String ok, String cancel, String title, String content, final OnOkClickListener listenerYes,final OnCancelClickListener listenerNo) AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage(content);/ 设置 title builder.setTitle(。
21、title);/ 设置确定按钮,固定用法声明一个按钮用这个 setPositiveButton builder.setPositiveButton(ok,new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int which) / 如果确定被电击 if (listenerYes != null) listenerYes.onOkClick(); mDialog = null; );/ 设置取消按钮,固定用法声明第二个按钮要用 setNegativeButton builder.set。
22、NegativeButton(cancel,new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int which) / 如果取消被点击 if (listenerNo != null) listenerNo.onCancelClick(); mDialog = null;);/ 控制这个 dialog 可不可以按返回键, true 为可以, false 为不可以 builder.setCancelable(false);/ 显示 dialogmDialog = builder.cre。
23、ate();if (!mDialog.isShowing()mDialog.show();public static void showDialog(Context context, int ok, int cancel, int title, int content, final OnOkClickListener listenerYes,final OnCancelClickListener listenerNo) showDialog(context, context.getString(ok), context.getString(cancel), context.getString(。
24、title), context.getString(content), listenerYes, listenerNo);static ProgressDialog progressDlg = null;/* 启动进度条* param strMessage 进度条显示的信息* param / 当前的 activity*/public static void showProgressDlg(Context ctx, String strMessage) if (null = progressDlg) if (ctx = null) return;progressDlg = new Progres。
25、sDialog(ctx);/设置进度条样式 progressDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);/提示的消息progressDlg.setMessage(strMessage);progressDlg.setIndeterminate(false);progressDlg.setCancelable(true);progressDlg.show();public static void showProgressDlg(Context ctx) showProgressDlg(ctx, );* 结束进度条*/public stat。
26、ic void stopProgressDlg() if (null != progressDlg & progressDlg.isShowing() progressDlg.dismiss();progressDlg = null;if (null != dialog & dialog.isShowing() dialog.dismiss();dialog = null;private static Dialog dialog;public static void showDialogForLoading(Context context, String msg, boolean cancel。
27、able) if (null = dialog) if (null = context) return;View view = LayoutInflater.from(context).inflate(R.layout.layout_loading_dialog,null);TextView loadingText = (TextView)view.findViewById(R.id.loading_tip_text); loadingText.setText(msg);dialog = new Dialog(context, R.style.loading_dialog_style); di。
28、alog.setCancelable(cancelable); dialog.setCanceledOnTouchOutside(cancelable); dialog.setContentView(iew, newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);Activity activity = (Activity) context;if (activity.isFinishing() return;dialog.show();。
29、 可能本博客也不是最好的解决方案,如果有更好的想法,我愿与你互相交流!分享: Retrofit+RxJava 错误预处理 看到 bobo_wang 的文章,不仅感觉有受益匪浅,这里做下介绍。首先定义如下 Transformer 转换器。public static Observable.Transformer, T sTransformer() return responseObservable - responseObservable.map(tResponse - if (!tResponse.success) throw new RuntimeException(tResponse.cod。
30、e);return tRata; ).onErrorResumeNext(new HttpResponseFunc Observable.Transformer switchSchedulers() return observable - observable.subscribeOn(Schedulers.io() .observeOn(AndroidSchedulers.mainThread();private static class HttpResponseFunc implements Func1 Override public Observable call(Throwable th。
31、rowable) /ExceptionEngine 为处理异常的驱动器return Observable.error(new Throwable(throwable);调用:public void login(View v)apiservice.login(name,pwd) .compose(Transformers.sTransformer() .compose(Transformers.switchSchedulers().subscribe(subscriber);private Subscriber subscriber = new Subscriber() Override pub。
32、lic void onCompleted() / do onCompletedOverride public void onError(Throwable e) / do on success != true;/ do on http error/ do on other errorOverride public void onNext(UserModel model) / parse data ;接口:FormUrlEncoded POST(interface?login)StringObservable login(Field(name) String name,Field(pwd) pw。
33、d);最后再来点干货。Transformer 和 Func 处理的区别 如上的处理,定义了 一个 sTransformer 和一个 HttpResponseFunc, 从中可以明显感觉的到 sTransformer 其实也是可以用 Func1 来定义的 ,public void login(View v)apiservice.login(name,pwd) .compose(Transformers.switchSchedulers().map(new TransFuc() .onErrorReturn(new HttpResponseFunc implements Func1, T Over。
34、ride public T call(Response tResponse) if (!tResponse.success) throw new RuntimeException(tResponse.code); return tResponse.data;Transformer 作用于整个流, Func1 是一个操作符 , 作用于数据项。 不规范数据的处理 有时候服务器返回的数据并不是十分规范的,比如正常返回是这样的success: true, / 是否成功status: 1, / 状态码data: / 内容错误时时这样的success: false, / 是否成功status: 0, / 。
35、状态码 data: 371 / 错误码 这时候如果我么用泛型处理 public class Response public boolean success;public String status; public T data;针对这种数据 ,我们的泛型该怎么写成了问题,错误的时候是 String, 正确的时候是 Bean?如果我们直接写成 JavaBea n那么我们会得到一个错误丄i nkedTreeM ap cannot be cast to xxx类型转换错误 .这时候只能将泛型写成String 来处理了 ,使用如下 Transformerpublic static Observable。
36、.Transformer trans() return stringObservable - stringObservable.map(s - Response parseJson = GsonUtil.parseJson(s, Response.class); if (null = parseJson) throw new RuntimeException(null = parseJson);if (PatternsUtil.isNum(parseJson.data.toString() throw new RuntimeException(parseJson.data.toString();return GsonUtil.parseJson(s, UserModel.class);).onErrorResumeNext(new HttpResponseFunc();使用就变成了如下这样 public void login(View v)apiservice.login(name,pwd).compose(Transformers.switchSchedulers().compose(Transformers.trans().subscribe(subscriber);封装的越来越简介了,用到实际项目吧。