我想要什么:
Observable<T>
目标
我创建一个BehaviourRelay
并订阅源Observable
并缓存其最后一个值。每当缓存失效时,我都会从源中取消订阅中继,然后再次将其重新订阅。
这是我到目前为止所拥有的:
class RxCache<T>(
private val observable: Observable<T>,
private val tag: String = "RxCache"
) {
private val source: Observable<T>
private var disposable: Disposable? = null
private val relay = BehaviorRelay.create<T>()
init {
// ) 1) create a new hot observable -
// as we will subscribe to it after every reload again
source = observable.share()
.doAfterNext {
L.d(tag, "data loaded")
}
// 2) first reload call
reload()
}
fun reload() {
// 1) unsubscribe from old observable
disposable?.dispose()
disposable = null
// 2) subscribe relay again to reload data
disposable = source.subscribe(relay)
}
fun observe(): Observable<T> {
return relay.hide()
.doAfterNext {
L.d(tag, "data emitted")
}
}
}
问题
我希望relay
仅订阅source
,如果它本身有一个订阅者,或者第一个订阅者订阅了中继。第一件事很容易,但是我不知道如何以安全的方式解决第二件事。
有什么想法吗?还是其他建议?
答案 0 :(得分:0)
您已经知道,不可能从BehaviorSubject
中“删除”最后一个值。我认为通过多种方式传递内部Observable的代码空手道不是一个好的解决方案。这是可以帮助您的代码:
sealed class CacheItem<T> { // (1)
class Data<T>(val data: T) : CacheItem<T>()
class Reset<T> : CacheItem<T>()
}
class RxCache<T> {
private val behaviorSubject: BehaviorSubject<CacheItem<T>> = BehaviorSubject.create()
fun reset() {
behaviorSubject.onNext(CacheItem.Reset()) // (2)
}
fun add(newItem: T) {
behaviorSubject.onNext(CacheItem.Data(newItem)) // (3)
}
fun observe() : Observable<T> {
return behaviorSubject.hide()
.filter { it != CacheItem.Reset<T>() } // (4)
.map { (it as CacheItem.Data<T>).data } // (5)
}
}
让我们解释一些有趣的标记部分:
subject
当前是否保存了缓存的数据,或者是否已执行重新加载/重置。 Reset
对象推向该对象,以指示没有可用的数据。CacheItem.Data
类中的数据推送到主题中即可。Data
项。CacheItem.Data
包装器并获取原始的缓存值。答案 1 :(得分:0)
我们来做低技术版本:
Map<T, Observable<T> caches = new ConcurrentHashMap<>();
/* .... */
caches.computeIfAbsent(key, k -> generateSourceObservable(k).cache())
.doOnNext(...) // or whatever, continue your processing pipeline.
然后,您只需清除或删除缓存中的键,现有的响应流就不会受到影响。