在項目開發中常常會在一個頁面中執行多個任務,多線程異步執行任務時哪個任務先結束出結果這些並不好控制,譬如要進行幾個併發的網絡請求在都拿到結果後需要對數據進行處理,希望的是用戶只感知一次數據加載,如果不能做到這樣,反饋到用戶界面的體驗也就不好了。通過 RxJava 的合併操作符我們能夠很方便的應對這些情況。
常用的幾個合併操作符
我們先創建如下三個不同數據類型的 observable 作爲示例數據
// 先創建三個不同類型的示例 observable
private val observable = Observable.fromArray(1, 2, 3)
.concatMap(object : Function<Int, ObservableSource<Int>> {
override fun apply(t: Int): ObservableSource<Int> {
return Observable.just(t).delay(1000, TimeUnit.MILLISECONDS)
}
})
private val observable1 = Observable.just("a", "b", "c")
.concatMap(object : Function<String, ObservableSource<String>> {
override fun apply(t: String): ObservableSource<String> {
return Observable.just(t).delay(400, TimeUnit.MILLISECONDS)
}
})
private val observable2 = Observable.fromArray(1.0f, 2.0f, 3.0f)
.concatMap(object : Function<Float, ObservableSource<Float>> {
override fun apply(t: Float): ObservableSource<Float> {
return Observable.just(t).delay(1000, TimeUnit.MILLISECONDS)
}
})
concat()
concat()
操作符將多個 Observable 按先後順序進行合併,當合並的 Observable<T> 泛型類型不一致時,事件流中的對象類型只能使用 Object
(java),Any
(kotlin)。通過如下示例代碼可以直觀的看到 concat 後事件的發送順序:
Observable.concat(observable, observable1)
.subscribe(object : AppCallBack<Any>() {
override fun success(data: Any?) {
println("contact----->$data")
}
override fun fail(code: Long?, msg: String?) {
}
override fun finish(success: Boolean) {
merge()
}
})
得到的輸出結果爲:
observable 發送 1、2、3 的時間間隔是大於 observable1發送 a、b、c 的間隔的,但輸出結果爲 123 打印完畢後再打印 abc 。這說明 concat 操作符是線性有序的,要等前一個 observable 發送完畢後纔會處理下一個 observable。當我們需要多個接口的返回數據按順序進行處理時可以使用 concat 操作符合並請求。
多於四個 observable 的合併:
兩種方式
-
concat()
傳入一個Iterable<? extends ObservableSource<? extends T>
對象 -
concatArray()
傳入一個 Observable 數組。
merge()
merge()
操作符將多個 Observable 無序合併,當合並的 Observable<T> 泛型類型不一致時,事件流中的對象類型只能使用 Object
(java),Any
(kotlin)。
Observable.merge(observable, observable1)
.subscribe(object : AppCallBack<Any>() {
override fun success(data: Any?) {
println("merge----->$data")
}
override fun fail(code: Long?, msg: String?) {
}
override fun finish(success: Boolean) {
zip()
}
})
得到的輸出結果爲:
abc 與 123 是按照時間先後順序交錯進行輸出的,說明
merge()
後事件的發送是併發的無序的,先發送先處理
多於四個 observable 的合併:
兩種方式
-
merge()
傳入一個Iterable<? extends ObservableSource<? extends T>
對象 -
mergeArray()
傳入一個 Observable 數組。
zip()
上面的兩種合併都是單個事件 item 訂閱監聽,如果想合併的事件 item 都接收到數據時處理這兩個事件數據就需要使用 zip() 操作符。
Observable.zip(observable, observable1, object : BiFunction<Int, String, String> {
override fun apply(t1: Int, t2: String): String {
return "t1=$t1 t2=$t2"
}
}).subscribe(object : AppCallBack<String>() {
override fun success(data: String?) {
println("zip----->$data")
}
override fun fail(code: Long?, msg: String?) {
}
override fun finish(success: Boolean) {
}
})
得到的輸出結果爲:
使用 zip 合併時,會等待每一次的合併項都發送完畢後再發送下一輪的事件。當我們需要從兩個數據源拿數據,但是需要統一合併顯示時可以使用 zip 操作符對事件流進行合併。
多個 observable 的合併:
zip()
的多事件合併就有點厲害了,支持九個 Observable 按數據類型合併,除了兩個觀察者對象合併時 zipper 是 BiFunction
其他的爲 FunctionX
,X 爲合併個數。如果多於九個觀察者對象合併,與上面兩種合併一樣可以使用 zipArray()
進行合併,但是合併後的觀察結果是一個 Object 數組對象,需要自己判斷數據類型
結語
除了以上的創建 Observable 對象級別的合併操作符,還有一些事件流中的操作符,譬如第一段代碼中的 concatMap
,在事件流前面添加其他事件的 startWith()
等。還是比較完善的