java优雅的处理异常_使用RxJava优雅的处理服务器返回异常

实际开发经常有这种情况,比如登录请求,返回来的并不会仅仅是User对象,而是被包装的RESTResult对象,RESTResult对象里,包括请求返回的状态:失败还是成功,错误码,User对象等等。

如下:

public class RESTResult {

public static final int FAILURE = 0; // 失败

public static final int SUCCESS = 1; // 成功

private int status; // 返回状态:0 失败 1 成功

private HttpResponseCode code; // 错误码

private String message; // 返回信息

private T data; // 包装的对象

// 其他省略

....

在使用Retrofit+RxJava的情况下,以登录为例,ApiService如下:

public interface ApiService {

@FormUrlEncoded

@POST(API + "account/login")

Observable> login(@Field("mobile") String mobile, @Field("code") String code);

我们对于登录返回的结果会这样处理:如果status为SUCCESS,则获取到User对象并进行后续操作;如果status为FAILURE,则需要根据code或者message提示用户相应的错误提示,并隐藏进度条对话框等操作。

下面有2种处理方式,方案1是我们没接触或刚接触Rx时会想到的方案,方案2里是比较优雅的处理方式 :)

方案1:

_apiService.login(mobile, verifyCode)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.doOnTerminate(() -> hideLoadingDialog())

.subscribe(new Action1>() {

@Override

public void call(RESTResult userRESTResult) {

if (result.getStatus() == RESTResult.FAILURE) {

HttpResponseCode code = result.getCode();

// 根据不同code进行不同处理

...

Toast.makeText(_context, result.getMessage(), Toast.LENGTH_SHORT).show();

} else {

User user = result.getData();

...

}

}

}, new Action1() {

@Override

public void call(Throwable throwable) {

throwable.printStackTrace();

Toast.makeText(_context, "请求失败,请稍后重试", Toast.LENGTH_SHORT).show();

}

});

显然这个方案有太多缺点:

1、RxJava建议在subscribe的时候,观察者应该拿到的是加工完成的数据源,而不是未加工的数据源;

2、在服务器返回status=FAILURE的情况下,异常是在onNext里处理,这样并不合适;

3、判断RESTResult的部分更应该放在链式操作里。

我们需要炫酷的Rx操作符!

最佳体验:

方案2:使用Observable.error(e):

_apiService.login(mobile, verifyCode)

.// 略 显示提示框、切换线程

.flatMap(result -> {

if (result.getStatus() == RESTResult.FAILURE) {

HttpResponseCode code = result.getCode();

// 根据不同code进行不同处理

...

return Observable.error(new ServerException(result.getMessage()));

}

return Observable.just(result.getData());

})

.subscribe(new Action1() {

@Override

public void call(User user) {

// user对象

}

}, new Action1() {

@Override

public void call(Throwable throwable) {

throwable.printStackTrace();

if (e instanceof ServerException){

Toast.makeText(_context, e.getMessage(), Toast.LENGTH_SHORT).show();

} else{

Toast.makeText(_context, "请求失败,请稍后重试", Toast.LENGTH_SHORT).show();

}

}

});

flaMap操作符可以接收一个Observable的输出作为输入,同时输出另外一个Observable。在服务器返回status=FAILURE的情况下,返回Observable.error(Throwable exception),SUCCESS的话,just源数据为一个新的Observable返回。

Observable.error(Throwable exception):

Returns an Observable that invokes an Observer's onError method when the Observer subscribes to it.

该方法是返回一个Observable,当观察者订阅时,执行观察者的onError方法。

这个方案完美的解决了方案1、2的问题:

1、观察者拿到“加工”完成的数据源;

2、异常方面,不管是服务器异常还是其他异常情况,最终观察者都可以接收到异常数据源,并最终统一在onError里处理。

3、使用flatMap处理RESTResult部分的代码,可以放在任意线程处理

最后:

方案2通过合适的封装,都可达到代码简化的目的。

封装部分可以查看我这篇简书:RxJava简洁封装之道

通过RxJava的链式操作,结合恰当的操作符,不仅可以把正常的数据源发射给观察者,同时也可以将错误异常数据源发射给观察者,RxJava远比想象中的强大!

方案2是目前我发现的最合适方案,如果还有更好的解决方案,欢迎告诉我哈~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值