我有一个io.reactivex.Observable
,它发出类型为T
的元素列表,这些列表可以用标识符(键)来区分。 Observable<List<T>>
每次排放List<T>
可以:
现在,我需要为处理所有更新的每个元素设置一个反应管道,并在不再发出更新时最终完成。因此,我想Òbservable.flatMap()each emitted list into an observable of observables of elements.
Observable>`
实际示例:假设我有一个热门观察对象,它发出一个列表 天气警报。警报可以在以下期间用新值更新 后续排放。随时可以发出新警报(一起 以及所有其他当前警报)。现在我必须处理每个警报 它的整个生命周期是分开的。对于每个警报,我需要一个专门的 可观察到,它发出初始值和所有更新,最后 完成。对于每个警报,我将动态创建一个专门的 消费者。
拳头发射看起来像这样:
[Alert1, Alert2]
-> 转型我预计会产生两种排放:第一种是可观测的 它本身发出Alert1
,第二个是另一个可观察到的 本身会发出Alert2
。第二次发射:
[Alert1, Alert2, Alert3]
->转换后 预期会有新的发射:本身发射Alert3
的可观察对象。 除了第一步中发射的两个可观察物 会分别发出一个新事件Alert1
Alert2
。第三次发射:
[Alert2, Alert3]
->我期望在转换之后 没有新的排放。但是第一个步骤发出的第一个可观察到的 现在完成,因为Alert1
不在列表中。另一个 从步骤1观察到的结果和从步骤2观察到的结果将各自发出Alert2
分别Alert3
。
转换函数将keySelector函数或任何其他方式作为参数来确定两个元素是否具有相同的标识符。对于遇到的每个新元素,它都应该发出可观察到的东西,从而依次发出该元素的初始状态和所有更新。
整个过程类似于groupBy运算符,但不同之处在于,它将元素列表作为输入,并且一旦收到不再包含该元素的列表,返回的Observable就会完成。
我编写了转换函数的示例实现,但它似乎效率低下,笨重且过于复杂。有谁有解决这个问题的更清洁的方法?
class GroupMapper<T, K> implements Function<List<T>, Observable<Observable<T>>> {
private final Function<T, K> keySelector;
private final HashMap<K, Observer<T>> groupsMap;
public GroupMapper(Function<T, K> keySelector) {
this.keySelector = keySelector;
this.groupsMap = new HashMap<>();
}
@Override
public Observable<Observable<T>> apply(List<T> list) {
List<T> newElements = new LinkedList<>();
List<T> updatedElements = new LinkedList<>();
List<Observer<T>> removedElements = new LinkedList<>();
list.forEach(el -> {
if (groupsMap.containsKey(keySelector.apply(el))) {
updatedElements.add(el);
} else {
newElements.add(el);
}
});
for (Iterator<Map.Entry<K, Observer<T>>> it = groupsMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<K, Observer<T>> entry = it.next();
if (list.stream().map(keySelector).noneMatch(entry.getKey()::equals)) {
removedElements.add(entry.getValue());
it.remove();
}
}
// dispose removed elements
removedElements.forEach(Observer::onComplete);
// update existing elements
updatedElements.forEach(el -> groupsMap.get(keySelector.apply(el)).onNext(el));
// add new elements
return Observable.fromIterable(newElements).map(el -> {
Subject<T> sub = BehaviorSubject.createDefault(el);
groupsMap.put(keySelector.apply(el), sub);
return sub;
});
}
}