我有以下代码
Observable.just(10)
.doOnTerminate(() -> Log.d("LOG", "ON TERMINATE"))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
int a = result / 0; // force an exception
}, error -> {
Log.d("LOG", "ERROR");
error.printStackTrace();
});
哪个会输出:
日志:已终止
日志:错误
但如果我将其修改为
Observable.just(10)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> Log.d("LOG", "ON TERMINATE"))
.subscribe(result -> {
int a = result / 0; // force an exception
}, error -> {
Log.d("LOG", "ERROR");
error.printStackTrace();
});
它只会给出 日志:错误
为什么第二个代码没有调用doOnTerminate
函数?
答案 0 :(得分:4)
我认为这是因为应该调用doOnTerminate的位置。在第一种情况下,它在新线程上调用。所以事件如下:
+-newThread-------------------------------------------------------------------------+
| emission ----- 10 -- |(completion because only one item was emitted) |
| doOnTerminate call(reason for calling is that emissions completed) |
+-mainThread------------------------------------------------------------------------+
| subscriber ----- 10(throw div/0)---X |
+-----------------------------------------------------------------------------------+
如果您了解just
operator如何在幕后实施,您会看到它在onCompleted
之后立即调用onNext
。
当你将doOnTerminate移动到主
时+-newThread-------------------------------------------------------------------------+
| emission ----- 10 -- |(completion because only one item was emitted) |
+-mainThread------------------------------------------------------------------------+
| doOnTerminate (not called) |
| subscriber ----- 10(throw div/0)->X |
+-----------------------------------------------------------------------------------+
不调用doOnTerminate
的原因是错误发生在订阅者的onNext部分。在这种情况下,LambdaObserver会直接检测到onNext
来电onError
中的错误(请参阅链接)。
我的测试代码:
final long[] start = {0};
Observable.just(10)
.subscribeOn(Schedulers.newThread())
.doOnNext(integer -> {
start[0] = System.currentTimeMillis();
message("onNext", start[0]);
})
.doOnTerminate(() -> message("doOnTerminate", start[0]))
.doFinally(() -> message("doFinally", start[0]))
.doAfterTerminate(() -> message("doAfterTerminate", start[0]))
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> message("doOnTerminate", start[0]))
.doFinally(() -> message("doFinally", start[0]))
.doAfterTerminate(() -> message("doAfterTerminate", start[0]))
.subscribe(integer -> {
message("Next", start[0]);
int a = integer / 0;
},
throwable -> message("ERROR", start[0])
);
void message(String message, long start) {
Log.d("LOG", message + " " + Thread.currentThread().getName() + " " + (System.currentTimeMillis() - start));
}
它的输出:
D/LOG: onNext RxNewThreadScheduler-1 0
D/LOG: doOnTerminate RxNewThreadScheduler-1 0
D/LOG: doAfterTerminate RxNewThreadScheduler-1 0
D/LOG: doFinally RxNewThreadScheduler-1 0
D/LOG: Next main 16
D/LOG: doFinally main 16
D/LOG: ERROR main 16
<强>解决方案强>
为了安全避免这种情况,同时由于缺少取消订阅(处置)事件,我会使用doFinally运算符。
所有这些都基于RxJava的2.0.4版本。
答案 1 :(得分:0)
doOnTerminate
或onError
上 onComplete
NOT 才能取消订阅。当在运算符之后发生错误时,只有取消订阅才会到达。
在.doOnUnsubscribe(() -> Log.d("LOG", "ON TERMINATE"))
之后添加doOnTerminate
。