我有一个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不会在不同的线程上运行,而且运行正常。
答案 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