【发布时间】:2023-03-11 13:47:01
【问题描述】:
在下面的代码中,我有一个嵌套的 observable。 flatMap 中的 sendMessage 调用 sendMessage 函数,该函数也是一个 observable。如果在这个嵌套的 observable 中发生异常,则假定 onExceptionResumeNext 会捕获异常,处理异常然后继续,就好像什么都没发生一样。异常确实被捕获,但是一旦对异常的处理完成,就不会在流中进行进一步的排放。甚至没有调用 doOnComplete。本质上,onExceptionResume next 只是挂起。
我尝试过 onErrorReturnItem 但结果相同。我没有在 Stackoverflow 或其他地方找到一个例子,它甚至在嵌套的 observable 中显示 onExceptionResumeNext 或 onErrorResumeNext 或 onErrorReturnItem ,经过一天的工作,我怀疑它可能无法支持嵌套的错误处理程序。
注意:在 onExceptionResumeNext 我目前只是返回
Observable.empty<MessageToSend>()
在我的实际代码中,我有处理异常的代码,我尝试返回一个 observable 以及只返回数据。不管我做什么 - 它总是挂起。
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 内的行上放置一个断点,它将在您第一次运行 observable 时被调用,而不仅仅是在抛出异常时。这显然是 RxJava 文档中未标识的行为。任何开发人员都会认为只有在抛出异常时才会调用它。在上面的示例中,将值设置为 10 并不是真正的问题。它实际上只是为发生异常的情况设置返回值。但是,如果这是在数据库中存储内容的更精细的代码(我的应用程序会这样做),那么它会在可观察对象初始化时被调用——这真的很糟糕。尽管有这个发现,它仍然没有解决我的问题,因为没有发出更多的项目。我在示例代码中发现的是,当调用 onExceptionResumeNext 时,也会调用 onComplete。太糟糕了,文档也没有提到。
【问题讨论】:
-
你把那些
onErrorResumeNext放在哪里了?我在提供的代码中没有看到它。把它放在可能失败的内部源上,而不是放在主序列中。 -
我使用的是onExceptionResumeNext,所以上面的代码没有显示onErrorResumeNext。但如前所述,没关系 - 如果我使用 onErrorResumeNext,问题仍然存在。主流和嵌套流需要自己的错误处理。我只是不完全相信这是可能的。还要记住,完全可以使用包含嵌套 observable 的第三方库,因此应该可以支持嵌套错误处理。
-
我认为你又遇到了 Kotlin 的歧义之一。你看,在
onExceptionResumeNext { }中,花括号创建了一个ObservableSource.subscribe(Observer)主体,它什么都不做,并且对你隐藏,因为it是可选的。用常规大括号替换花括号,看看这是否有助于onExceptionResumeNext。 -
用圆括号替换花括号会导致 onExceptionResumeNext 一直被调用。我的假设是圆括号强制调用方法,而花括号提供匿名回调。