我有一个虚拟网络数据源:
fun networkDataSource(): Single<List<Int>> {
return Single.just((0 until 100).toList())
.delay(150, TimeUnit.MILLISECONDS)
}
这里是无尽的观察。主要用途是它的计算应该是“受保护的”,因此它仅计算一次它的单个值。 (此处为1。)
val endless = Observable
.just(1)
.observeOn(Schedulers.io())
.delay(500, TimeUnit.MILLISECONDS)
// Counts as heavy operation, do not calculate this here once again
.doOnNext { println("=> E: Calculated once") }
.cache()
//.doOnNext { println("=> E: From cache") }
.repeat()
主流只是发出值:
val mainStream = Observable.range(0, 6)
.doOnNext { println("=> M: Main stream $it") }
任务:
将这三个可观察对象压缩在一起,并优化网络使用率,以至于调用它的次数不会超过必要。 (一旦满足数据数量(在这种情况下为整数)。
方法:
mainStream
.concatMap {index ->
Observables.zip(
Observable.just(index),
endless,
networkDataSource()
.toObservable()
.doOnNext { println("#> N: Network data fetch $index") }
)
}
.doOnNext { println("=> After concatmap: ${it.first}") }
.take(4)
.doOnNext { println("=> After take: ${it.first}") }
.subscribe(
{ println("=> Last onnext") },
{ it.printStackTrace() },
{ synchronized(check) { check.notifyAll() } }
)
完成锁定的线程-仅用于测试:
synchronized(check) {
check.wait()
}
println("Ending")
以下是输出:
=> M: Main stream 0
=> M: Main stream 1
=> M: Main stream 2
=> M: Main stream 3
=> M: Main stream 4
=> M: Main stream 5
#> N: Network data fetch 0
=> E: Calculated once
=> After concatmap: 0
=> After take: 0
=> Last onnext
#> N: Network data fetch 1
=> After concatmap: 1
=> After take: 1
=> Last onnext
此输出,在第二次拍摄后卡住。 (不会在一分钟内进行)。我的问题是,为什么会这样?
作为旁注,如果我取消注释endless
中可观察到的行:
.doOnNext { println("=> E: From cache") }
它将用该行填充控制台。为什么endless
每次迭代都被调用这么多次?
flatMap()
在这里不是解决方案,因为它没有考虑take(4)
并继续完成所有网络呼叫。
那我怎样才能使concatMap()
工作呢?
(我还添加了 RxJS 标记,因为这是一个反应性问题,绝对不是Kotlin的问题。如果RxJava库中存在这些功能,也欢迎使用JS解决方案。)
编辑。
我查看了代码,结果2的输出可能是由于prefetch
参数造成的:
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
return concatMap(mapper, 2);
}
但是我仍然不明白它是如何工作的。我只读过concatMap()
是flatmap()
,但它等待每个结果。
答案 0 :(得分:1)
从评论中:
在第一项之后,整个设置可能会在同一线程上运行,并且CONCAT()
中的repeat
将永远不会放弃该线程,从而阻止了其他任何运算符的进行。对我而言,重复endless
是没有意义的,因为您将只使用其中一项,并且仅使用其中一项。