我正在开发一个应用程序,显示从互联网上获取的项目列表。 我有2个按钮loadMore并刷新,loadMore - 加载下一批项目,刷新 - 从头开始加载项目。
我正在使用MVI(模型视图意图)模式。 为了简单起见,我创建了一个使用数字列表的示例,每个数字代表一批项目:
val loadSubject = BehaviorSubject.create<Unit>()
val refreshSubject = PublishSubject.create<Unit>()
val list = loadSubject.scanWith(
{ Observable.just(emptyList<Int>()) },
{ listObservable, _ ->
listObservable
.map { it + ++count }
.replay().autoConnect()
}
)
.flatMap { it }
.filter { it.isNotEmpty() }
val listSubscription = {
list.subscribe {
//do whatever with the list
}
}
refreshSubject.scanWith(
listSubscription,
{ disposable, _ ->
disposable.dispose()
listSubscription()
}
).subscribe()
所以现在它可以完美地运行,但订阅是在我的Intent中,我需要一个使用Rx的方法,它可以做同样的事情,但让我的View订阅。
我想要的是:
我的列表是[1,2,3]
on loadMore按ill get [1,2,3,4]
刷新时按下病例[5]
答案 0 :(得分:0)
val loadSubject = PublishSubject.create<Unit>()
val refreshSubject = PublishSubject.create<Unit>()
val loadMoreSequence = defer {
loadSubject.scanWith(
{ Observable.just(listOf(0)) },
{ listObservable, _ ->
listObservable
.map { it + it.size }
.replay().autoConnect()
}
)
.flatMap { it }
}
val list = concat(Unit.asObservable(), refreshSubject)
.switchMap { loadMoreSequence }
// testing
list.subscribe {
println(it)
}
loadSubject.onNext(Unit)
loadSubject.onNext(Unit)
refreshSubject.onNext(Unit)
loadSubject.onNext(Unit)
结果:
[0]
[0, 1]
[0, 1, 2]
[0]
[0, 1]
答案 1 :(得分:0)
我设法得到了一些工作:
val loadSubject = PublishSubject.create<Unit>()
val refreshSubject = PublishSubject.create<Unit>()
val loadList: (ItemsProvider) -> Observable<SingleEvent<List<Int>>> = { provider ->
val markedGet = Observable.fromCallable(provider::fetchItem)
.markStartAndEnd()
loadSubject.concatWith(Unit)
.flatMapWithDrop(markedGet)
.publish().autoConnect()
}
val listEvents = refreshSubject.concatWith(Unit)
.switchMap { loadList(itemsProvider) }
val list = refreshSubject.concatWith(Unit)
.switchMap {
listEvents.filter { it is SingleEvent.Result }
.map { (it as SingleEvent.Result).data }
.scan { list: List<Int>, newList: List<Int> ->
list + newList
}
}
val isListEmpty = list.map { it.isEmpty() }
val isDownloading = listEvents.map { it.isRunning() }
val isRefreshing =
Observable.merge(
refreshSubject.map { true },
isDownloading.filter { !it }.skip(1)
)
扩展名为:
fun <T> Observable<T>.concatWith(item: T): Observable<T> =
Observable.concat(Observable.just(item), this)
sealed class SingleEvent<T> {
class Start<T> : SingleEvent<T>()
data class Result<T>(val data: T) : SingleEvent<T>()
}
fun <T> Observable<T>.markStartAndEnd(): Observable<SingleEvent<T>> {
return this.map { SingleEvent.Result(it) as SingleEvent<T> }
.startWith(SingleEvent.Start())
}
/**
* Flatmaps upstream items into [source] items.
* Ignores upstream items if there is any [source] instance is currently running.
*
* upstream ----u-----u---u-------u---------------|-->
* ↓ ↓ ↓
* source ---s-------|-> ---s-------|-> ↓
* ↓ ↓ ↓
* result -------s-----------------s------------|-->
*/
fun <T, R> Observable<T>.flatMapWithDrop(source: Observable<R>): Observable<R> =
this.toFlowable(BackpressureStrategy.DROP)
.flatMap({ source.toFlowable(BackpressureStrategy.MISSING) }, 1)
.toObservable()
基于Dmitry Ryadnenko blog post。
但我无法使flatMapWithDrop工作,因为我正在进行网络调用,我需要删除任何传入的刷新请求,直到当前的刷新请求结束。
更新:有没有其他方法可以缓存列表(不再使用refreshSubject.concatWith(Unit).switchMap {}
)?