结合嵌套Observable的最新值

时间:2018-09-21 23:04:48

标签: android kotlin rx-java rx-java2

我有一些自定义字段,每个自定义字段都有一个可以使用BehaviorSubject<Value>进行检索的值。显示的字段是基于我从API中获得的信息,因此最后我有n个BehaviorSubject<Value>。我想将这些值组合到一个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>>的方式,但是我不知道该怎么做。

1 个答案:

答案 0 :(得分:1)

groupBy在这里似乎对我没有帮助。

通常使用scan完成值的累加,在这里您可以使用如下转换:

values.scanWith({ arrayOfNulls<Value>(N) }) { acc, (index, value) ->
    acc.copyOf().apply {
        set(index, value)
    }
}
    .map { it.filterNotNull() }

如果没有copyOf(),您可能会逃脱,但是我认为过去,当累加器功能不纯净时,我会遇到问题。

顺便说一句,您可以写position to value而不是Pair(position, value)

此外,您可以使用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")
    }