上一篇讲到RxJava的基本用法,但只是正常使用还是不够的,我们在进行网络操作时难免遇到错误的情况,那遇到这些情况时应该怎样处理呢?
String BASE_URL = "http://123.57.248.61:8089/";
@GET()
Call<TokenModel> getToken();
@GET()
Call<ChargeModel> getCharge(@Query("token") String token);
@GET()
Call<ChargeModel> getCharge();
这里先贴出需要的方法。
现在假设一种情况,我们在查询用户余额时需要先从网络获取一个token来保证安全性(有点牵强),请求token之后需要把token作为参数再从网络请求余额,如果用Retrofit需要这么写:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getToken().enqueue(new Callback<TokenModel>() {
@Override
public void onResponse(Call<TokenModel> call, Response<TokenModel> response) {
apiManger.getCharge(response.body().getToken()).enqueue(new Callback<ChargeModel>() {
@Override
public void onResponse(Call<ChargeModel> call, Response<ChargeM
}
@Override
public void onFailure(Call<ChargeModel> call, Throwable t) {
}
});
}
@Override
public void onFailure(Call<TokenModel> call, Throwable t) {
}
});
ok,但是请求余额token并不是必要的参数,如果请求token失败后我们还想获取余额,那么就需要这样写:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getToken().enqueue(new Callback<TokenModel>() {
@Override
public void onResponse(Call<TokenModel> call, Response<TokenModel> response) {
apiManger.getCharge(response.body().getToken()).enqueue(new Callback<ChargeModel>() {
@Override
public void onResponse(Call<ChargeModel> call, Response<ChargeModel> response) {
}
@Override
public void onFailure(Call<ChargeModel> call, Throwable t) {
}
});
}
@Override
public void onFailure(Call<TokenModel> call, Throwable t) {
apiManger.getCharge().enqueue(new Callback<ChargeModel>() {
@Override
public void onResponse(Call<ChargeModel> call, Response<ChargeModel> response) {
}
@Override
public void onFailure(Call<ChargeModel> call, Throwable t) {
}
});
}
});
谜之缩进毁一生,这尼玛都是什么鬼啊?这里的需求虽然有些奇葩,但在开发过程中难免会遇到,下面我们看一下RxJava怎样优雅的处理这种情况:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getToken()
.flatMap(new Func1<TokenModel, Observable<ChargeModel>>() {
@Override
public Observable<ChargeModel> call(TokenModel tokenModel) {
return apiManger.getCharge(tokenModel.getToken());
}
})
.onErrorResumeNext(new Func1<Throwable, Observable<ChargeModel>>() {
@Override
public Observable<ChargeModel> call(Throwable throwable) {
return apiManger.getCharge();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ChargeNodel>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ChargeModel chargeModel) {
}
});
先来分析一下这段代码,首先调用getToken获取token之后再调用flatMap方法重新发射流,从这儿之后传递的对象就变成chargeModel了,再往后面遇到了一个onErrorResumeNext操作符,这就是RxJava错误处理的一个操作符,那这个操作符是什么意思呢?onErrorResumeNext操作符接收的是前面传递过来的错误,接收到错误之后就会重新发射一个流,但是如果前面一切正常没有错误发生的话,那这个操作符是不会执行的,这就好比前面的流水线出了故障,就会切换到这条流水线上,但是如果前面的流水线没有问题,这条流水线是不会被启动的。结合我们前面的需求看一下,首先获取token,如果获取成功,则会传递到flatMap中启动获取余额的流,获取余额之后传递到onNext方法中,如果获取token失败,则会传递到onErrorResumeNext中,接着调用无参的getCharge,这样也可以获取余额。
看到这里是不是感觉万事大吉了呢,不要高兴的太早,前面说到onErrorResumeNext会接收前面所有的错误,试想一下这种情况:如果我们在获取token的时候成功了,但是在获取余额的时候失败了,按照Retrofit的做法获取余额失败后就什么操作也没有,既然获取余额都失败了就没必要在做什么了,但是如果按照上面RxJava的写法,不管在哪一步失败他都会执行onErrorResumeNext的,这可不是我们想要的,因为我们无法精准控制哪一步失败需要重新请求,试想如果操作的层次更多的话,难不成每次失败都要进入onErrorResumeNext重新请求一次吗?不过办法总是有的,我们说过flatMap就是重新发射一条流,既然他是一条流,那他完全可以在发射的时候继续添加错误处理,解决办法如下:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getToken()
.flatMap(new Func1<TokenModel, Observable<ChargeNodel>>() {
@Override
public Observable<ChargeModel> call(TokenModel tokenModel) {
return apiManger.getCharge(tokenModel.getToken()).onErrorResumeNext(new Func1<Throwable, Observable<? extends ChargeModel>>() {
@Override
public Observable<? extends ChargeModel> call(Throwable throwable) {
return Observable.empty();
}
});
}
})
.onErrorResumeNext(new Func1<Throwable, Observable<ChargeModel>>() {
@Override
public Observable<ChargeModel> call(Throwable throwable) {
return apiManger.getCharge();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ChargeModel>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ChargeModel chargeModel) {
}
});
我们在flatMap发射流的时候又添加了一个onErrorResumeNext操作符,如果发生错误,那他就会进入后面的onErrorResumeNext,直接返回Observable.empty(),最后调用onCompleted方法。使用retrolambda可以简化成如下代码:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getToken()
.flatMap(tokenModel -> apiManger.getCharge(tokenModel.getToken()).onErrorResumeNext(throwable -> Observable.empty()))
.onErrorResumeNext(throwable1 -> apiManger.getCharge())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(chargeModel -> {
}, throwable2 -> {
});
这尼玛也太精简了吧,可以与前面用Retrofit的代码对比一下。好了,本篇文章到此结束,如有错误,欢迎指出!
网友评论