简介
zip(图片来源于官方文档).pngzip操作符用于将多个数据源合并,并生成一个新的数据源。新生成的数据源严格按照合并前的数据源的数据发射顺序,并且新数据源的数据个数等于合并前发射数据个数最少的那个数据源的数据个数。
举个例子
测试场景
@Test
fun zip() {
val observable_1 = Observable.fromIterable(listOf(1, 2))
val observable_2 = Observable.fromIterable(listOf("a", "b", "c", "d"))
val observable_3 = Observable.fromIterable(listOf("A", "B", "C", "D", "E", "F"))
Observable
.zip(
observable_1,
observable_2,
observable_3,
Function3<Int, String, String, String> { t1, t2, t3 ->
println("old data t1:$t1")
println("old data t2:$t2")
println("old data t3:$t3")
t1.toString() + t2 + t3
}
)
.subscribe {
println("new data:$it")
println("===================")
}
}
结果:
old data t1:1
old data t2:a
old data t3:A
new data:1aA
===================
old data t1:2
old data t2:b
old data t3:B
new data:2bB
===================
真实场景
比如说我之前项目中的一个场景:
数据1来源于本地数据库,数据2来源于服务器,合并之后再做一系列的业务操作,于是我美滋滋的写成了这样:
override fun getMoreUsedAmount() {
val obervable_1 = Observable
.create<User> { emitter ->
val last = DB.queryLast(view.context, BaseAccessibilityService.TYPE_ALI, Configuration.getUserInfoByKey(Constants.KEY_ACCOUNT))
if (last != null)
emitter.onNext(last)
emitter.onComplete()
}
val request = HashMap<String, String>()
request["mchId"] = Configuration.getUserInfoByKey(Constants.KEY_MCH_ID)
val obervable_2 = service.getMoreUsedAmount(SignRequestBody(request).sign())
Observable
.zip(obervable_1, obervable_2, BiFunction<User?, ResultEntity<List<ConstantAmountDto>>?, List<MoreUsedBean>> { lastUser, t2 ->
BaseAccessibilityService.moreUsedAmount.clear()
val list = mutableListOf<MoreUsedBean>()
t2.result
?.filter {
val result = lastUser.account.isEmpty()
|| lastUser.mode != BaseAccessibilityService.MODE_MORE_USED
|| it.constantAmount > lastUser.pos_curr
list.add(MoreUsedBean(it.constantAmount, !result))
result
}
?.forEach { BaseAccessibilityService.moreUsedAmount.offer(it) }
list
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : ProgressSubscriber<List<MoreUsedBean>>(view.context) {
override fun _onNext(t: List<MoreUsedBean>) {
view.showMoreUsedAmount(t)
}
override fun _onError(error: String?) {
view.showHint(error ?: "未知错误")
}
})
}
有毛病吗?乍一看好像还可以,简单测试下也通过了,发布后却得到反馈,说是得不到数据,一脸的懵逼,于是我换了个新手机试了试,发现是这样的:
error.png
说是我们主动取消了请求,一番探索,终于发现问题出在了数据源1上面,因为新装应用时本地数据库是空的,所以数据源1没有发射数据,直接调用了onComplete。而zip合并后的数据源是合之前数据个数最少的数据源数据个数一样,所以数据源2直接取消了请求,正确方式应该这样:
val obervable_1 = Observable
.create<User> { emitter ->
val last = DB.queryLast(view.context, BaseAccessibilityService.TYPE_ALI, Configuration.getUserInfoByKey(Constants.KEY_ACCOUNT))
if (last != null)
emitter.onNext(last)
else
emitter.onNext(User())
emitter.onComplete()
}
网友评论