我有一些自定义字段,每个字段都有一个可以使用BehaviorSubject< Value>检索的值.显示的字段基于我从API获得的内容,因此最后我有大量的BehaviorSubject< Value> s.我想将这些值组合成一个Observable< List< Value>>其中列表包含来自这些字段的最新值(顺序无关紧要).然而问题是这些字段并非全部同时可用,因为它们是在UI加载时创建的,所以我不能将Observable.combineLatest与主题列表一起使用.
我目前所做的是创建了以下变量:
private val values = BehaviorSubject.create<Pair<Int, Value>>()
我使用这个主题来订阅所有场地的主题,但首先将他们的位置映射到主题并制作一对.
fieldSubject.map {
Pair(position, value)
}.subscribe(values)
我当时想要做的是根据它们在对中的位置对值进行分组,得到一个Observable< List< Value>>其中列表包含每个位置的最新值.但是我不知道在使用groupBy对它们进行分组后如何继续:
values.groupBy {
it.first
}
这导致Observable< GroupedObservable< Pair,Value>>>.最后,我认为我应该看到Observable< List< Value>>,但我不知道该怎么做.
最佳答案 groupBy在这里似乎对我没有帮助.
累积值通常使用扫描完成,在这里您可以使用如下转换:
values.scanWith({ arrayOfNulls<Value>(N) }) { acc, (index, value) ->
acc.copyOf().apply {
set(index, value)
}
}
.map { it.filterNotNull() }
你可能没有copyOf()就可以逃脱,但我认为在过去累积函数不纯的时候遇到了问题.
顺便说一下,您可以将位置写入值而不是Pair(位置,值).
此外,您可以使用merge来获取Observable< Pair< Int,Value>>而不是创建一个BehaviorSubject并手动将其订阅到所有字段:
Observable.mergeArray(
fieldX.map { 0 to it },
fieldY.map { 1 to it },
fieldZ.map { 2 to it }
// ...
)
总的来说,你可以拥有一个为你完成所有功能的功能:
inline fun <reified T : Any> accumulateLatest(vararg sources: Observable<out T>): Observable<List<T>> {
return Observable.merge(sources.mapIndexed { index, observable ->
observable.map { index to it }
})
.scanWith({ arrayOfNulls<T>(sources.size) }) { acc, (index, value) ->
acc.copyOf().apply {
set(index, value)
}
}
.map { it.filterNotNull() }
}
然后打电话:
accumulateLatest(fieldX, fieldY, fieldZ)
.subscribe {
println("Latest list: $it")
}