我有一个可观察的对象,它可能会失败,但有一个特殊的例外,在这种情况下,我想显示一个带有重试按钮的对话框。我看到了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,但是没有运气。

我已经使用不在单独线程上运行的简单可观察对象测试了我的代码,并且工作正常。

最佳答案

您可以通过flatMap ping一个PublishSubject来完成此操作,然后在按下相关按钮后对其进行更新。这是一个经典的Java Swing示例。

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);
    }
}

编辑:

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

编辑2
我已撤消了更改,因此答案再次有意义。

09-26 21:23