RxJava2.0 使用过程中遇到的 bug 总结

Author Avatar
dev.liang 6月 27, 2019
  • 在其它设备中阅读本文章

日常开发中遇到的 RxJava2.0 问题,在这里进行一个简单的记录,也希望可以帮助到更多被这些问题困扰的小伙伴们,持续更新…

io.reactivex.exceptions.UndeliverableException

RxJava2 取消订阅后,抛出的异常无法捕获,导致程序崩溃:
详细异常打印日志:(io.reactivex.exceptions.UndeliverableException:The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with.)

UndeliverableException 从字面意思看,意思是不可送达的异常。
通过源码跟踪,发现抛出io.reactivex.exceptions.UndeliverableException 唯一地方是 RxJavaPlugins 类。

RxJava2 当取消订阅后(dispose()),RxJava 抛出的异常后续无法接收(此时后台线程仍在跑,可能会抛出IO等异常),全部由 RxJavaPlugin 接收,需要提前设置 ErrorHandler.

RxJava2的一个重要的设计理念是:不吃掉任何一个异常。产生的问题是,当RxJava2“downStream”取消订阅后,“upStream”仍有可能抛出异常,这时由于已经取消订阅,“downStream”无法处理异常,此时的异常无人处理,便会导致程序崩溃。

个人出问题的代码,也是常规写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Observable.create((ObservableOnSubscribe<HouseVOListSchema>) emitter -> {
if (isViewAttached()) {
try {
ResultBean result = apiInstance.requestData(token);
if (result == null) {
emitter.onError(new NullPointerException());
} else {
emitter.onNext(result);
emitter.onComplete();
}
} catch (ApiException e) {
Trace.e("Rxjava 接口调用异常", "getSearchPageIndex123 e.getMessage() "+e.getMessage() + " e.getCode() "+e.getCode()+" e.getResponseBody() " +e.getResponseBody());
emitter.onError(e);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
// Memory leak
.as(mMvpView.bindAutoDispose())
.subscribe(result -> {
mMvpView.dismissLoading();
if (isViewAttached()) {
if (AppConstant.RESPONSE_RESULE_CODE == result.getCode()) {
mMvpView.onSuccess(result.getResult());
} else {
mMvpView.onError(result.getMessage());
}
}
}, throwable -> mMvpView.onThrowable(throwable)
);

就这种常规操作的代码,出问题了。

解决方案:在 Application 初始化时候设置 RxJavaPlugin 的 ErrorHandler

1
2
3
4
5
6
private void setRxJavaErrorHandler() {
RxJavaPlugins.setErrorHandler(throwable -> {
throwable.printStackTrace();
Trace.e("MyApplication", "MyApplication setRxJavaErrorHandler " + throwable.getMessage());
});
}