当嵌套错误处理程序调用onExceptionResumeNext时,observable停止发出

时间:2019-07-16 12:41:40

标签: kotlin rx-java2

在下面的代码中,我有一个嵌套的Observable。 flatMap中的sendMessage调用sendMessage函数,这也是一个可观察到的函数。如果在此嵌套可观察的对象中发生异常,则假设onExceptionResumeNext可以捕获该异常,处理该异常,然后继续进行,就好像什么都没有发生一样。确实捕获到异常,但是一旦完成对异常的处理,流中将不再产生任何排放。甚至没有调用doOnComplete。本质上,onExceptionResume接下来只是挂起。

我尝试了onErrorReturnItem,但结果相同。我没有在Stackoverflow或其他地方找到一个单独的示例,该示例甚至在嵌套的可观察对象内显示onExceptionResumeNext或onErrorResumeNext或onErrorReturnItem,并且在处理了一天之后,我怀疑可能无法支持嵌套的错误处理程序。

注意:在onExceptionResumeNext中,我目前正返回

Observable.empty<MessageToSend>()

在我的实际代码中,我有处理异常的代码,我尝试返回一个可观察的对象以及仅返回数据。没关系,我总是挂着。

fun postMessages() {
    val msgToSendPublisher = BehaviorSubject.createDefault(MessageToSend())

    msgToSendPublisher
        .flatMap { _ ->
            App.context.repository.getMessageToSend().toObservable()
        }
        .doOnError { error ->
            if (error is EmptyResultSetException)
                App.context.repository.setSendStatusToNotSendingForAllMessages()
        }
        .doOnNext { messageToSend ->
            App.context.repository.updateMessage(messageToSend)
        }
        .flatMap { messageToSend ->
            App.context.repository.sendMessage(messageToSend)
        }
        .doOnNext { messageToSend ->
            messageToSend.dateSent = Date()
            App.context.repository.updateDateLastMessageSent(messageToSend)
        }
        .doOnNext { messageToSend ->
            if (messageToSend.totalMessagesToSend == 1)
                App.context.repository.updateSendStatus(messageToSend, MessageSendStates.NOT_SENDING)
            else
                Observable.just(messageToSend)
        }
        .doOnNext {
            msgToSendPublisher.onNext(it)
        }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            { messageToSend ->

            },
            { ex ->
                onMessagesSent()
            },
            {
                onMessagesSent()
            }
        )
}


fun sendMessage(messageToSend: MessageToSend): Observable<MessageToSend> {
    val obs = Observable.fromCallable {
            if (messageToSend.totalMessagesToSend == 3)
                throw Exception("Couldn't send to recipient.")

            messageToSend
        }.map {
            storeMessageSent(messageToSend)
        }.onExceptionResumeNext {
            Observable.empty<MessageToSend>() // Hangs here.
        ).doOnComplete {
            addNewMessageIfRequired(messageToSend, newMessage)
        }

        return obs
}

更新:

我决定测试一个发现的示例代码,该示例代码使用onExceptionResumeNext。看起来像这样:

    Observable.fromArray(1, 2, 3)
        .doOnNext {
            if (it == 2) {
                throw (RuntimeException("Exception on 2"))
            }
        }
        .onExceptionResumeNext(
            Observable.just(10)
        )
        .subscribe(
            {
                var x = it
            },
            {
                var x = it
            },
            {
                var x = 0
                x++
            }
        )

如果在onExceptionResumeNext内部的行上放置一个断点,则每当您第一次运行可观察对象时,不仅在引发异常时,都会调用该断点。显然,这是RxJava文档中未发现的行为。任何开发人员都会感到只有在引发异常时才会调用它。在上面的示例中,将值设置为10确实不是问题。它实际上是为异常发生时的情况设置返回值。但是,如果这是更复杂的代码将内容存储在数据库中(我的应用程序执行此操作),则在初始化observable时将调用它-这确实很糟糕。尽管有这个发现,它仍然不能解决我的问题,因为没有其他物品被放出。我在示例代码中发现的是,当调用onExceptionResumeNext时,也调用了onComplete。太糟糕了,文档也没有提到。

1 个答案:

答案 0 :(得分:1)

您可能想使用defer来推迟执行函数调用,这些函数调用会导致副作用:

Observable<Integer> createFallback() {
    System.out.println("Why is this executing now?!");
    return Observable.empty();
}

Observable.<Integer>error(new Exception())
.onExceptionResumeNext(createFallback())
.subscribe();

createFallback之所以运行,是因为您通过调用将其指定为运行。如果序列被重写,原因应该更加明显:

Observable<Integer> fallback = createFallback();

Observable.<Integer>error(new Exception())
.onExceptionResumeNext(fallback)
.subscribe();

现在,如果您注释掉可观察错误的部分,它是否仍执行createFallback()?是的,RxJava甚至还没有参与。

如果您不希望这种副作用不会发生在createFallback上,则必须推迟执行整个方法,为此可以使用一个运算符:defer

Observable.<Integer>error(new Exception())
.onExceptionResumeNext(Observable.defer(() -> createFallback()))
.subscribe();

我认为在Kotlin中看起来像这样:

Observable.error(new Exception())
.onExceptionResumeNext(Observable.defer { createFallback() })
.subscribe()