RxJava onErrorResumeNext调度程序

时间:2015-06-17 10:45:33

标签: java android rx-java

我有一个observable可能会因特殊异常而失败,在这种情况下我想显示一个带有重试按钮的对话框。我已经看到this回答,但它并没有完全符合我的要求。我无法使用retryWhen来解决我的问题,因此我使用了onErrorResumeNext。如果您能想出办法retryWhen,请告诉我们。

现在我有这段代码:

public Observable<Order> proceedWithOrdering(Activity activity) {
    return apiService.createOrder()
            .subscribeOn(Schedulers.io())
            .compose(applyRetryLogic(activity))
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.mainThread());
}

public <T extends ApiResponse> Observable.Transformer<T, T> applyRetryLogic(Activity activity) {
    return observable -> observable
            .onErrorResumeNext(retry(observable, activity))
            .subscribeOn(AndroidSchedulers.mainThread());
}

public <T> Func1<Throwable, ? extends Observable<? extends T>> retry(Observable toRetry, Activity activity) {
    return throwable -> {
        if (throwable instanceof NetworkException) {
            MaterialDialog dialog = retryDialog(activity);
            View retry = dialog.getActionButton(DialogAction.POSITIVE);
            View cancel = dialog.getActionButton(DialogAction.NEGATIVE);
            Observable<Object> retryClick = RxView.clicks(retry).map(o -> {
                dialog.dismiss();
                return o;
            });
            Observable<Object> cancelClick = RxView.clicks(cancel).flatMap(o -> {
                dialog.dismiss();
                return Observable.error(throwable);
            });

            dialog.show();

            return Observable.amb(retryClick, cancelClick)
                    .flatMap(o -> toRetry.compose(applyRetryLogic(activity)));
        } else {
            return Observable.error(throwable);
        }
    };
}

问题是call内的retry不会在主线程上执行,而是会引发Can't create handler inside thread that has not called Looper.prepare()异常。

问题是 - 如何强制它在主线程上执行?正如您所看到的,我已经尝试在subscribeOn(AndroidSchedulers.mainThread())compose之后立即执行onErrorResumeNext而没有运气。

我使用简单的observable来测试我的代码,这些observable不会在不同的线程上运行,而且运行正常。

2 个答案:

答案 0 :(得分:3)

您可以通过flatMap ping PublishSubject来完成此操作,然后在按下相关按钮后更新public class RetryWhenEnter { public static void main(String[] args) { AtomicInteger d = new AtomicInteger(); Observable<Integer> source = Observable.just(1); source.flatMap(v -> { if (d.incrementAndGet() < 3) { return Observable.error(new RuntimeException()); } return Observable.just(v); }) .retryWhen(err -> { return err.flatMap(e -> { System.out.println(Thread.currentThread() + " Error!"); PublishSubject<Integer> choice = PublishSubject.create(); SwingUtilities.invokeLater(() -> { int c = JOptionPane.showConfirmDialog(null, e.toString() + "\r\nRetry?", "Error", JOptionPane.YES_NO_OPTION); if (c == JOptionPane.YES_OPTION) { choice.onNext(1); } else { choice.onCompleted(); } }); return choice; }); }).subscribe(System.out::println, Throwable::printStackTrace); } } 。这是一个经典的Java Swing示例。

observeOn(AndroidSchedulers.mainThread())

修改

或者在onErrorResumeNext之前或使用retryWhen retryWhen(o -> o.observeOn(AndroidSchedulers.mainThread())...)时使用strsplit

编辑2 我已经回滚了这个改变,所以答案又有意义了。

答案 1 :(得分:2)

有一种方法可以使用CascadeType.MERGE来解决我的问题(感谢@akarnokd):

retryWhen