这个问题与this question松散相关,但没有答案。 Bob Dalgleish的答案很接近,但是不支持来自Single的潜在错误(我认为OP实际上也是如此)。
我基本上正在寻找一种“过滤错误”的方法 - 但是当查找基于RX时,不要认为这存在。我试图获取值列表,通过查找运行它们,并跳过任何返回查找失败的结果(throwable)。我无法弄清楚如何以反应的方式实现这一目标。
我尝试了各种形式的error handling operators与映射相结合。过滤器仅适用于原始值 - 或者至少我无法弄清楚如何使用它来支持我想要做的事情。
在我的用例中,我迭代一个ID列表,从远程服务请求每个ID的数据。如果服务返回404,则该项目不再存在。我应该从本地数据库中删除不存在的项目并继续处理ID。流应该返回查找值列表。
这是一个松散的例子。如何编写getStream()以便canFilterOnError传递?
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import org.junit.Test
class SkipExceptionTest {
private val data: Map<Int, String> = mapOf(
Pair(1, "one"),
Pair(2, "two"),
Pair(4, "four"),
Pair(5, "five")
)
@Test
fun canFilterOnError() {
getStream(listOf(1, 2, 3, 4, 5))
.subscribeOn(Schedulers.trampoline())
.observeOn(Schedulers.trampoline())
.test()
.assertComplete()
.assertNoErrors()
.assertValueCount(1)
.assertValue {
it == listOf(
"one", "two", "four", "five"
)
}
}
fun getStream(list: List<Int>): Single<List<String>> {
// for each item in the list
// get it's value via getValue()
// if a call to getValue() results in a NotFoundException, skip that value and continue
// mutate the results using mutate()
TODO("not implemented")
}
fun getValue(id: Int): Single<String> {
return Single.fromCallable {
val value: String? = data[id]
if (value != null) {
data[id]
} else {
throw NotFoundException("dat with id $id does not exist")
}
}
}
class NotFoundException(message: String) : Exception(message)
}
答案 0 :(得分:3)
我最终将getValue()
映射到Optional<String>
,然后在其上调用onErrorResumeNext()
并返回Single.error()
或Single.just(Optional.empty())
。从那里,主流可以过滤掉空的Optional。
private fun getStream(list: List<Int>): Single<List<String>> {
return Observable.fromIterable(list)
.flatMapSingle {
getValue(it)
.map {
Optional.of(it)
}
.onErrorResumeNext {
when (it) {
is NotFoundException -> Single.just(Optional.empty())
else -> Single.error(it)
}
}
}
.filter { it.isPresent }
.map { it.get() }
.toList()
}
答案 1 :(得分:2)
首先 .materialize(),然后 .filter()关于非错误事件,然后 .dematerialize()
getStream(/* ... */)
.materialize()
.filter(notification -> { return !notification.isOnError(); })
.dematerialize()