Android-RxJavaRxjava相关RxAndroid & RxJava

RxJava(二)错误处理

2016-08-10  本文已影响1371人  请你吃鱼

上一篇讲到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的代码对比一下。好了,本篇文章到此结束,如有错误,欢迎指出!

上一篇 下一篇

猜你喜欢

热点阅读