observeOn()会影响doOnTerminate()调用

时间:2017-01-25 12:41:10

标签: android rx-java

我有以下代码

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函数?

2 个答案:

答案 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)

仅在doOnTerminateonError

onComplete NOT 才能取消订阅。当运算符之后发生错误时,只有取消订阅才会到达。

.doOnUnsubscribe(() -> Log.d("LOG", "ON TERMINATE"))之后添加doOnTerminate