OdysseyxJava2 实战连串作品

ENVISIONxJava2 实战知识梳理(1) – 后台执行耗费时间操作,实时通报 UI
更新

索罗德xJava2 实战知识梳理(2) –
计算一段时间内数据的平均值

CR-VxJava2 实战知识梳理(3) –
优化搜索联想成效

奇骏xJava2 实战知识梳理(4) – 结合 Retrofit
请求信息资源音信

猎豹CS6xJava2 实战知识梳理(5) –
不难及进阶的轮询操作

LANDxJava2 实战知识梳理(6) –
基于错误类型的重试请求

LX570xJava2 实战知识梳理(7) – 基于 combineLatest
实现的输入表单验证

QashqaixJava2 实战知识梳理(8) – 使用 publish + merge
优化先加载缓存,再读取互联网数据的请求进程

奇骏xJava2 实战知识梳理(9) – 使用 timer/interval/delay
完毕职务调度

RubiconxJava2 实战知识梳理(10) – 荧屏旋转导致 Activity
重建时上涨职分

普拉多xJava2 实战知识梳理(11) –
检查和测试网络状态并机关心器重试请求

LANDxJava2 实战知识梳理(12) – 实战讲解 publish & replay & share & refCount
& autoConnect

大切诺基xJava2 实战知识梳理(13) –
怎么着使得错误产生时不自行终止订阅关系

景逸SUVxJava2 实战知识梳理(14) – 在 token 过期时,刷新过期 token
并再一次发起呼吁

福睿斯xJava2 实战知识梳理(15) – 完毕2个差不离的 MVP + 猎豹CS6xJava + Retrofit
应用


一、前言

1.1 应用背景

在互联网请求时,有时候会油不过生要求展开重试的景况,重试的时候,有以下几点需求留意:

  • 限制重试的次数
  • 基于错误类型,判断是或不是要重试
  • 依照错误类型,等待特定的年月未来再去重试

大家先来看一下脚下的某个网络框架是咋做的?通过分析Volley的源码,可以从BasicNetwork的代码中见到,它是将互连网请求的代码都置身3个无限的while(true)巡回当中,借使发生了尤其,会在中间的catch语句中开始展览拍卖,尽管须要持续重试,那么就吞掉这几个特别,并将重试次数加1,那样就会进去下三次的while(true)巡回去拜访网络;如若不要求重试,那么就抛出那几个这一个,退出那么些极端循环。也正是实现了后边两点须要。

上边大家就来演示怎么样通过RxJava2来轻松实现地点的三点供给,通过那篇小说,大家将学习retryWhen操作符的现实性用法,retryWhenrepeatWhen平常被世家用来相比较,若是对repeatWhen感兴趣的同班可以阅读上一篇小说
KugaxJava2 实战知识梳理(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的输入是2个Observable<Throwable>,输出是1个泛型ObservableSource<?>。若是大家收起Observable<Throwable>出殡的音讯,那么就足以获取上游发送的不当类型,并遵照该项目进行响应的处理。
  • 假设出口的Observable发送了onComplete或者onError则象征不须要重订阅,截至全数流程;不然触发重订阅的操作。也正是说,它
    偏偏是用作1个是否要触发重订阅的关照onNext出殡的是什么数据并不根本。
  • 对此每便订阅的多寡流 Function
    函数只会回调三遍
    ,并且是在onError(Throwable throwable)的时候接触,它不会接受任何的onNext事件。
  • Function函数中,不可能不对输入的
    Observable<Object>实行拍卖
    ,这里大家使用的是flatMap操作符接收上游的数额,对于flatMap的演说,大家能够参考
    宝马X5xJava2 实战知识梳理(4) – 结合 Retrofit
    请求信息资源新闻

2.2 retryWhen 和 repeatWhen 对比

TiggoxJava2 实战知识梳理(5) –
不难及进阶的轮询操作

中大家曾经对repeatWhen开始展览了介绍,让大家再来看一下它的法则图:

repeatWhen 原理图

能够看看,retryWhenrepeatWhen最大的不比正是:retryWhen是收到onError后触发是不是要重订阅的摸底,而repeatWhen是通过onComplete触发。

2.3 依据 Throwable 的花色选用响应的重试策略

是因为上游能够因此onError(Throwable throwable)中的非常文告retryWhen,那么大家就足以根据万分的门类来控制重试的政策。

就像是我们在上头例子中做的那么,大家因而flatMap操作符获取到足够的品类,然后依照非凡的类型选取动态地决定推迟重试的时间,再用Timer操作符达成延迟重试;当然,对于有些老大,大家能够间接选用不重试,即直接回到Observable.empty或者Observable.error(Throwable throwable)


更加多小说,欢迎访问笔者的 Android 知识梳理种类:

网站地图xml地图