AndroidRxJava+Retrofit⽹络异常、状态码统⼀处理
Android RxJava+Retrofit ⽹络异常捕获、状态码统⼀处理
前⾔
近来使⽤RxJava+Retrofit进⾏开发,在项⽬中遇到这样⼀个需求,联⽹请求获得数据异常时,需要将对应的Message和StatusCode进⾏获得并展⽰,⽐如:
1.服务器连接Error: 对应的返回404,500等等;
2.没有⽹络状态(没有4g,3g,是否处于wifi环境下等);
参考⽂章:
@码⼩⽩
⼀、简单的获取处理
最简单的处理⽅式,直接对返回的throwable进⾏类型判断处理:
//先判断⽹络环境
if(!NetUtils.is4G(context)){
return;
}
//再联⽹请求,对throwable进⾏判断
.getModelResult(param1, param2)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Model>(){
@Override
public void onCompleted(){
}
@Override
public void onError(Throwable e){
if(e instanceof HttpException){
//获取对应statusCode和Message
HttpException exception =(HttpException)e;
String message = sponse().message();
int code = sponse().code();
}else if(e instanceof SSLHandshakeException){
//接下来就是各种异常类型判断...
}else if(){
}...
...
}
@Override
public void onNext(Model model){
}
});
显然,代码并不难以理解,但是⾮常⿇烦,总不⾄于每次都要进⾏这样的⼤块代码复制粘贴吧。
请注意,进⾏类型判断的的HttpException为
import java.HttpException;
所以需要我们依赖:
compile 'fit2:adapter-rxjava:2.1.0'
⼆、NetErrorUtil封装
1.⾸先我们创建⼀个Throwable的管理类
public class ExceptionHandle {
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 handleException(Throwable e){
ResponeThrowable ex;
Log.i("tag","e.toString = "+ e.toString());
if(e instanceof HttpException){
HttpException httpException =(HttpException) e;
ex =new ResponeThrowable(e, ERROR.HTTP_ERROR);
de()){
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.code = de();
break;
}
return ex;
}else if(e instanceof ServerException){
ServerException resultException =(ServerException) e;
unknown怎么处理ex =new ResponeThrowable(resultException, de);            ex.message = ssage;
return ex;
}else if(e instanceof JsonParseException
|| e instanceof JSONException
/*|| e instanceof ParseException*/){
ex =new ResponeThrowable(e, ERROR.PARSE_ERROR);
return ex;
}else if(e instanceof ConnectException){
ex =new ResponeThrowable(e, ERROR.NETWORD_ERROR);
return ex;
}else if(e instanceof javax.ssl.SSLHandshakeException){
ex =new ResponeThrowable(e, ERROR.SSL_ERROR);
return ex;
}else{
ex =new ResponeThrowable(e, ERROR.UNKNOWN);
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);
}
}
/**
* ServerException发⽣后,将⾃动转换为ResponeThrowable返回
*/
class ServerException extends RuntimeException {
int code;
String message;
}
}
在这个类中,我们把throwable进⾏类型统⼀判断:
1.若为Exception,我们再进⾏判断,根据不同种类的Exception,转化为ResponeThrowable返回,并赋予不同的code和message;
2.若为RuntimeException,我们再转换为ResponeThrowable返回;
总⽽⾔之,我们把获取到的异常,通过handleException()⽅法,转化为统⼀的ResponeThrowable返回,这个对象包含code和message。
2.然后是创建⼀个新的Subscriber基类
/**
* Subscriber基类,可以在这⾥处理client⽹络连接状况
* (⽐如没有wifi,没有4g,没有联⽹等)
* Created by fcn-mq on 2017/4/19.
*/
public abstract class MySubscriber<T>extends Subscriber<T>{
private Context context;
public MySubscriber(Context context){
}
@Override
public void onStart(){
Log.i("tag","Start()");
//接下来可以检查⽹络连接等操作
if(!NetworkUtil.isNetworkAvailable(context)){
Toast.makeText(context,"当前⽹络不可⽤,请检查⽹络情况", Toast.LENGTH_SHORT).show();
// ⼀定好主动调⽤下⾯这⼀句,取消本次Subscriber订阅
if(!isUnsubscribed()){
unsubscribe();
}
return;
}
}
@Override
public void onError(Throwable e){
Log.e("tag","MySubscriber.throwable ="+e.toString());
Log.e("tag","MySubscriber.throwable ="+e.getMessage());
if(e instanceof Exception){
//访问获得对应的Exception
onError(ExceptionHandle.handleException(e));
}else{
//将Throwable 和未知错误的status code返回
onError(new ExceptionHandle.ResponeThrowable(e,ExceptionHandle.ERROR.UNKNOWN));
}
}
public abstract void onError(ExceptionHandle.ResponeThrowable responeThrowable);
@Override
public void onCompleted(){
Log.i("tag","Complete()");
}
}
这个就好理解了,我们可以在基类中统⼀进⾏客户端⽹络环境的判断,或者当⽹络异常发⽣时,统⼀转换为
ResponeThrowable,在onError(ExceptionHandle.ResponeThrowable responeThrowable)中回调,这个abstract的回调⽅法需要我们⾃⼰实现。
3.代码中使⽤:
new Retrofit.Builder()
.baseUrl(ConstantsApi.BASE_DOUBAN)
.ate())
.ate())
.client(client)
.build()
.create(DoubanMovieService.class)//获得对应的service对象
.getModelResult(param1, param2)//⽹络请求
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MySubscriber<Model>(context){
@Override
public void onNext(Model model){
...
}
@Override
public void onError(ExceptionHandle.ResponeThrowable throwable){
LogUtil.m("tag","throwable ="+ String());
//接下来就可以根据状态码进⾏处理...
int statusCode = de;
switch(statusCode){
case ExceptionHandle.ERROR.SSL_ERROR:
break;
case ExceptionHandle.ERROR.UNKNOWN:
break;
case ExceptionHandle.ERROR.PARSE_ERROR:
break;
case ExceptionHandle.ERROR.NETWORD_ERROR:
break;
case ExceptionHandle.ERROR.HTTP_ERROR:
break;
}
}
});
最后是NetErrorUtil的源码地址:
【GitHub地址】
2018/9/25更新
时隔⼀年,笔者发现本⽂的实现⽅式,在很多情况下有 很⼤的限制性(直⽩点吧,就是上⽂的⽅式太low了),因此修改了实现的⽅式,并归纳出⼀个在我看来 更灵活,更轻量 的⼯具组件,更适合 RxJava2的重度使⽤者,详情请参考:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。