RxJava2 实战系列文章

RxJava2 实战知识梳理(1) – 后台执行耗时操作,实时通报 UI
更新
RxJava2 实战知识梳理(2) –
计算一段时间内数据的平均值
RxJava2 实战知识梳理(3) –
优化搜索联想功能
RxJava2 实战知识梳理(4) – 结合 Retrofit
请求新闻消息
RxJava2 实战知识梳理(5) –
简单和进阶的轮询操作
RxJava2 实战知识梳理(6) –
基于左类型的重试请求
RxJava2 实战知识梳理(7) – 基于 combineLatest
实现之输入表单验证
RxJava2 实战知识梳理(8) – 使用 publish + merge
优化先加载缓存,再念博网络数据的呼吁过程
RxJava2 实战知识梳理(9) – 使用 timer/interval/delay
实现任务调度
RxJava2 实战知识梳理(10) – 屏幕旋转导致 Activity
重建时回升任务
RxJava2 实战知识梳理(11) –
检测网络状态并活动重试请求
RxJava2 实战知识梳理(12) – 实战讲解 publish & replay & share & refCount
& autoConnect
RxJava2 实战知识梳理(13) –
如何令错误有常莫活动停止订阅关系
RxJava2 实战知识梳理(14) – 在 token 过期时,刷新过期 token
并更发起呼吁
RxJava2 实战知识梳理(15) – 实现一个简短的 MVP + RxJava + Retrofit
应用


一、前言

1.1 应用背景

每当网要时,有时候会现出得进行重试的景况,重试的上,有以下几点需要专注:

  • 范围重试的次数
  • 因错误类型,判断是否如重试
  • 据悉错误类型,等待特定的时以后还去重试

俺们先行来拘禁一下手上底部分大网框架是怎么开的?通过分析Volley的源码,可以从BasicNetwork的代码中看到,它是拿网络要的代码都位于一个绝的while(true)循环中,如果产生了十分,会于里头的catch告句被展开拍卖,如果急需继续重试,那么即便吞掉这个非常,并拿重试次数加1,这样虽见面进来下同样不好的while(true)巡回去访问网络;如果无欲重试,那么即便抛出这好,退出者太循环。也便是落实了前方两接触需要。

下面我们虽来演示如何通过RxJava2来轻松实现者的老三接触需要,通过就首文章,我们将修retryWhen操作符的具体用法,retryWhenrepeatWhen时不时给大家之所以来比,如果对repeatWhen谢谢兴趣之校友可以看上同首文章
RxJava2 实战知识梳理(5) –
简单和进阶的轮询操作。

2.2 示例代码

以下面的事例中,我们一共发起了五糟糕呼吁,也不怕是subscribe面临的代码,其中前四次等呼吁都调用onError计通知下游请求失败,同时带动达了由定义之错误信息wait_shortwait_long,第五差才回正确的多寡。

当我们收起错误后,会依据错误的色确定重试的时日,同时,我们尚保留了目前重试的次数,避免太次的重试请求。如果需要重试,那么通过Timer操作符延时指定的年华,否则回Observable.error(Throwable)舍重试。

public class RetryActivity extends AppCompatActivity {

    private static final String TAG = RetryActivity.class.getSimpleName();
    private static final String MSG_WAIT_SHORT = "wait_short";
    private static final String MSG_WAIT_LONG = "wait_long";

    private static final String[] MSG_ARRAY = new String[] {
            MSG_WAIT_SHORT,
            MSG_WAIT_SHORT,
            MSG_WAIT_LONG,
            MSG_WAIT_LONG
    };

    private TextView mTvRetryWhen;
    private CompositeDisposable mCompositeDisposable;
    private int mMsgIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_retry);
        mTvRetryWhen = (TextView) findViewById(R.id.tv_retry_when);
        mTvRetryWhen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startRetryRequest();
            }
        });
        mCompositeDisposable = new CompositeDisposable();
    }

    private void startRetryRequest() {
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {

            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                int msgLen = MSG_ARRAY.length;
                doWork();
                //模拟请求的结果,前四次都返回失败,并将失败信息递交给retryWhen。
                if (mMsgIndex < msgLen) { //模拟请求失败的情况。
                    e.onError(new Throwable(MSG_ARRAY[mMsgIndex]));
                    mMsgIndex++;
                } else { //模拟请求成功的情况。
                    e.onNext("Work Success");
                    e.onComplete();
                }
            }

        }).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {

            private int mRetryCount;

            @Override
            public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
                return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {

                    @Override
                    public ObservableSource<?> apply(Throwable throwable) throws Exception {
                        String errorMsg = throwable.getMessage();
                        long waitTime = 0;
                        switch (errorMsg) {
                            case MSG_WAIT_SHORT:
                                waitTime = 2000;
                                break;
                            case MSG_WAIT_LONG:
                                waitTime = 4000;
                                break;
                            default:
                                break;
                        }
                        Log.d(TAG, "发生错误,尝试等待时间=" + waitTime + ",当前重试次数=" + mRetryCount);
                        mRetryCount++;
                        return waitTime > 0 && mRetryCount <= 4 ? Observable.timer(waitTime, TimeUnit.MILLISECONDS) : Observable.error(throwable);
                    }

                });
            }

        });
        DisposableObserver<String> disposableObserver = new DisposableObserver<String>() {

            @Override
            public void onNext(String value) {
                Log.d(TAG, "DisposableObserver onNext=" + value);
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "DisposableObserver onError=" + e);
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "DisposableObserver onComplete");
            }
        };
        observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(disposableObserver);
        mCompositeDisposable.add(disposableObserver);
    }

    private void doWork() {
        long workTime = (long) (Math.random() * 500) + 500;
        try {
            Log.d(TAG, "doWork start,  threadId=" + Thread.currentThread().getId());
            Thread.sleep(workTime);
            Log.d(TAG, "doWork finished");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上述代码的运行结果吧,红框中的间距就是每次等待重试的日:

老二、示例解析

2.1 retryWhen 介绍

retryWhen的规律图如下所示:

retryWhen 原理图

retryWhen提供了 重订阅
的功能,对于retryWhen来说,它的重订阅触发有些许碰元素:

  • 上游通知retryWhen此次订阅流已经完结,询问该是否需要还订阅,该询问是盖onError事件触发的。
  • retryWhen根据onError的档次,决定是否需要再行订阅,它通过返回一个ObservableSource<?>来通知,如果该ObservableSource返回onComplete/onError,那么非会见触发重订阅;如果发送onNext,那么会触发重订阅。

实现retryWhen的关键在于如何定义其的Function参数:

  • Function的输入是一个Observable<Throwable>,输出是一个泛型ObservableSource<?>。如果我们收起Observable<Throwable>发送的音信,那么即使可以取上游发送的错类型,并依据该品种进行响应的拍卖。
  • 使出口的Observable发送了onComplete或者onError尽管意味着未待再行订阅,结束所有流程;否则触发重订阅的操作。也就是说,它
    不过是作一个是不是如触发重订阅的通onNext发送的凡啊数据并无紧要。
  • 对各一样潮订阅的数目流 Function
    函数仅仅会回调一不好
    ,并且是在onError(Throwable throwable)的时光接触,它不会见吸收任何的onNext事件。
  • Function函数中,不能不对输入的
    Observable<Object>进行拍卖
    ,这里我们应用的是flatMap操作符接收上游的数目,对于flatMap的解说,大家可以参考
    RxJava2 实战知识梳理(4) – 结合 Retrofit
    请求新闻消息 。

2.2 retryWhen 和 repeatWhen 对比

在 RxJava2 实战知识梳理(5) –
简单和进阶的轮询操作
中我们已经对repeatWhen展开了介绍,让咱们更来拘禁一下它的规律图:

repeatWhen 原理图

得视,retryWhenrepeatWhen顶深的差便是:retryWhen是收到onError继点是否如重复订阅的打听,而repeatWhen是通过onComplete触发。

2.3 根据 Throwable 的类别选择响应的重试策略

鉴于上游可以经onError(Throwable throwable)蒙之十分通知retryWhen,那么我们就可根据异常的品种来决定重试的国策。

纵使像咱在上面例子中举行的那么,我们经过flatMap操作符获取到大的路,然后因异常的型选择动态地控制推迟重试的时日,再就此Timer操作符实现延迟重试;当然,对于一些死,我们可以直接选择未重试,即直接归Observable.empty或者Observable.error(Throwable throwable)


重复多篇,欢迎访问我的 Android 知识梳理系列:

  • Android
    知识新濠娱乐梳理目录:http://www.jianshu.com/p/fd82d18994ce
  • 个人主页:http://lizejun.cn
  • 私文化总结目录:http://lizejun.cn/categories/
网站地图xml地图