让我为如何在RX中做到这一点而烦恼。
T 实际用例是将LowerLevelEvent(val userId:String)映射到HigherLevelEvent(val user:User),其中Observable提供了User,因此它可以发出n次,输出
LowerLevelEvent1(abc) -> HigherLevelEvent1(userAbc(nameVariation1)
LowerLevelEvent2(abc) -> HigherLevelEvent2(userAbc(nameVariation1)
LowerLevelEvent3(abc) -> HigherLevelEvent3(userAbc(nameVariation1)
LowerLevelEvent4(abc) -> HigherLevelEvent4(userAbc(nameVariation1)
HigherLevelEvent4(userAbc(nameVariation2)
HigherLevelEvent4(userAbc(nameVariation3)
所以我的幼稚解决方案是使用CombineLatest。因此,在userId不变的情况下,订阅了observable的用户,即在新的lowerLevelEmits及其userId不变的情况下不重新订阅
val _lowerLevelEventObservable: Observable<LowerLevelEvent> = lowerLevelEventObservable
.replayingShare()
val _higherLevelEventObservable: Observable<HigherLevelEvent> = Observables
.combineLatest(
_lowerLevelEventObservable,
_lowerLevelEventObservable
.map { it.userId }
.distinctUntilChanged()
.switchMap { userRepository.findByIdObservable(it)
) { lowerLevelEvent, user -> createHigherLevelInstance... }
但是这有一个小问题,因为CombineLatest中的两个来源都来自相同的可观察对象。
然后我想到了
lowerLevelObservable.
.switchMap { lowerLevelEvent ->
userRepository.findByIdObservable(lowerLevelEvent.userId)
.map { user -> createHigherLevelInstance... }
}
但是,如果lowerLevelObservable快速发出,则此操作可能会中断,并且由于用户可观察项可能需要一些时间,因此可以跳过给定的lowerLevelX事件,而我不能这样做。此外,它还会重新订阅用户可观察到的每次发射,这很浪费,因为它极不可能发生变化
那么,也许concatMap?那个问题是用户可观察的对象没有完成,所以concatMap无法工作。
有人知道吗?
非常感谢
//澄清: 基本上是将A变体(A1,A2 ..)映射到A'变体(A1',A2'..)的映射,同时将查询对象附加到该对象,在该对象中是可观察到的查询,因此在进行映射后可能会重新查询AX'需要与新的查询结果一起发布。但是查询很冷,无法完成
例如A1(1) -> A1'(user1), A2(1) -> A2'(user1), A3(1) -> A3'(user1)
的示例-现在有人在应用程序的其他位置更改了user1,因此下一个发出的是A3'(user1')
答案 0 :(得分:1)
根据您的评论,以下内容将在RxSwift中运行。我不知道如何将其转换为RxJava。不过,老实说,我认为这里存在对Rx的根本滥用。祝你好运。
工作原理:如果允许订阅,它将进行订阅,否则它将事件添加到缓冲区中以备后用。如果当前未订阅内部事件,或者当前已订阅的内部Observable发出了元素,则允许订阅。
警告:它不能正确处理当前的完成情况。我会把它留给您作为练习。
func example(lowerLevelEventObservable: Observable<LowerLevelEvent>, userRepository: UserRepository) {
let higherLevelEventObservable = lowerLevelEventObservable
.flatMapAtLeastOnce { event in // RxSwift's switchLatest I think.
Observable.combineLatest(
Observable.just(event),
userRepository.findByIdObservable(event.userId),
resultSelector: { (lowLevelEvent: $0, user: $1) }
)
}
.map { createHigherLevelInstance($0.lowLevelEvent, $0.user) }
// use higherLevelEventObservable
}
extension ObservableType {
func flatMapAtLeastOnce<U>(from fn: @escaping (E) -> Observable<U>) -> Observable<U> {
return Observable.create { observer in
let disposables = CompositeDisposable()
var nexts: [E] = []
var disposeKey: CompositeDisposable.DisposeKey?
var isAllowedToSubscribe = true
let lock = NSRecursiveLock()
func nextSubscription() {
isAllowedToSubscribe = true
if !nexts.isEmpty {
let e = nexts[0]
nexts.remove(at: 0)
subscribeToInner(e)
}
}
func subscribeToInner(_ element: E) {
isAllowedToSubscribe = false
if let key = disposeKey {
disposables.remove(for: key)
}
let disposable = fn(element).subscribe { innerEvent in
lock.lock(); defer { lock.unlock() }
switch innerEvent {
case .next:
observer.on(innerEvent)
nextSubscription()
case .error:
observer.on(innerEvent)
case .completed:
nextSubscription()
}
}
disposeKey = disposables.insert(disposable)
}
let disposable = self.subscribe { event in
lock.lock(); defer { lock.unlock() }
switch event {
case let .next(element):
if isAllowedToSubscribe == true {
subscribeToInner(element)
}
else {
nexts.append(element)
}
case let .error(error):
observer.onError(error)
case .completed:
observer.onCompleted()
}
}
_ = disposables.insert(disposable)
return disposables
}
}
}