我想在完成之前查找要找到的整个项目列表,如果找不到整个列表,则抛出异常(超时或自定义)。就像内置的Observable.timer()一样,但是一旦发出第一个项目而不是测试传递,我希望它能够找到列表中的所有项目。
这是一个例子。假设我有一些测试函数可以发出Observable< FoundNumber>。它看起来像这样:
var emittedList: List<String?> = listOf(null, "202", "302", "400")
data class FoundNumber(val numberId: String?)
fun scanNumbers(): Observable<FoundNumber> = Observable
.intervalRange(0,
emittedList.size.toLong(),
0,
1,
TimeUnit.SECONDS).map { index ->
FoundNumber(emittedList[index.toInt()]) }
然后将调用该函数以获取将与预期数字列表进行比较的数字。如果scanForNumbers中有其他数字不在“目标”列表中,则无关紧要。他们将被忽略。像这样:
val expectedNumbers = listOf("202", "302","999")
scanForNumbers(expectedNumbers)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe { value -> Log.d(TAG, "Was returned a $value") }
因此,预期数字(202,302和999)与将要发射的数字(202,302和400)不完全匹配。因此,应该发生超时,但是使用Observable.timer()的内置版本,由于至少观察到一个项目,因此不会超时。
这是我想要的。任何人都知道如何在RxJava / RxKotlin中编写代码吗?
fun scanForNumbers(targets: List<String>): Observable<FoundNumber> {
val accumulator: Pair<Set<Any>, FoundNumber?> = targets.toSet() to null
return scanNumbers()
.SPECIAL_TIMEOUT_FOR_LIST(5, TimeUnit.SECONDS, List)
.scan(accumulator) { acc, next ->
val (set, previous) = acc
val stringSet:MutableSet<String> = hashSetOf()
set.forEach { stringSet.add(it.toString()) }
val item = if (next.numberId in stringSet) {
next
} else null
(set - next) to item // return set and nullable item
}
.filter { Log.d(TAG, "Filtering on ${it.second}")
it.second != null } // item not null
.take(targets.size.toLong()) // limit to the number of items
.map { it.second } // unwrap the item from the pair
.map { FoundController(it.numberId) } // wrap in your class
}
你如何编码,希望使用RxJava / Kotlin,如上所述在列表上超时的方法?
答案 0 :(得分:0)
我想我现在知道了,你希望超时从你订阅的那一刻开始计算,而不是在你观察物品之后。
如果这是您所需要的,那么takeUntil
运营商可以帮助您:
return scanNumbers()
.takeUntil(Observable.timer(5, TimeUnit.SECONDS))
.scan(accumulator) { acc, next -> ...
在这种情况下,计时器将在您订阅后立即开始计时。如果主要观察者在那之前完成,那么很好,如果没有,那么计时器将完成主要的观察结果。
但是takeUntil
本身不会抛出错误,它只会完成。如果您需要以错误结束,那么您可以使用以下组合:
return scanNumbers()
.takeUntil(
Observable
.error<Void>(new TimeoutError("timeout!"))
.delay(5, TimeUnit.SECONDS, true))
.scan(accumulator) { acc, next -> ...