我觉得我不了解RxJava2的错误处理方法。 (顺便说一下,我已经阅读了RxJava2 observable take throws UndeliverableException并且我理解会发生什么,但不确切地说为什么或者是否有更好的方式来处理它而不是我在下面讨论的内容。我也看到了RuntimeException thrown and not caught in RxJava2 Single after it has been disposed和它看起来并不完全相关。)
让我们说我有以下非常简化的例子:
val sub = Observable.fromCallable(callableThatCanReturnNull)
.subscribe({ println(it) }, { System.err.println(it) })
按顺序发生以下事件序列:
sub.dispose()
Callable
返回null。查看RxJava2源代码,我看到了:
@Override
public void subscribeActual(Observer<? super T> s) {
DeferredScalarDisposable<T> d = new DeferredScalarDisposable<T>(s);
s.onSubscribe(d);
if (d.isDisposed()) {
return;
}
T value;
try {
value = ObjectHelper.requireNonNull(callable.call(), "Callable returned null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
if (!d.isDisposed()) {
s.onError(e);
} else {
RxJavaPlugins.onError(e);
}
return;
}
d.complete(value);
}
显然,在第一次d.isDisposed()
支票和第二次d
之间的某个时间,RxJavaPlugins.onError(e)
被处理,因此我们点击e
,NullPointerException
为ObjectHelper.requireNonNull()
(来自RxJavaPlugins.setErrorHandler()
)。如果我们没有用某些东西调用 GlobalErrorFilter errorFilter = new GlobalErrorFilter(BuildConfig.DEBUG /* alwaysCrash */);
RxJavaPlugins.setErrorHandler(t -> {
if (errorFilter.filter(t)) {
// Crash in some cases
throw new RuntimeException(t);
} else {
// Just log it in others
Logger.e("RxError", t, "Ignoring uncaught Rx exception: %s", t.getLocalizedMessage());
}
});
,那么默认行为是抛出一个会导致应用程序崩溃的致命异常。这看起来很糟糕(tm)。我目前的做法如下:
GlobalErrorFilter
我的fromCallable
考虑了这个UndeliverableException
案例以及class GlobalErrorFilter(private val alwaysCrash: Boolean = false) {
/**
* Returns `true` if app should crash; `false` otherwise. Prefers to return `true`.
*/
fun filter(t: Throwable) = when {
alwaysCrash -> true
t is UndeliverableException -> false
t.localizedMessage.contains("Callable returned null") -> false
else -> true
}
}
。事实上,它看起来像这样:
{{1}}
这个感觉非常hackish。我想要的是告诉RxJava如果我处理了一个observable,我不关心是否(1)它发出新项目(2)它完成(3)它是onErrors。我只是不在乎。如果没有这个全局错误处理程序,有没有办法做到这一点?