當前位置:
首頁 > 最新 > 當Kotlin遇見RxJava多數據源

當Kotlin遇見RxJava多數據源

最近Kotlin語言一直佔據熱搜榜,褒貶不一,但我想說,不管有什麼想法都要拋在腦後,畢竟Google爸爸出手,你不情願也要跟隨它的步伐。鑒於此,本篇對RxJava多數據源的總結是基於Kotlin語言,也讓大家明白,使用Kotlin開發應用並不是不能使用Java庫,現在有一部分人擔心,Kotlin第三方庫那麼少,如果使用Kotlin開發那不是給自己找罪受,其實你完全錯了,當你說這話的時候,我敢斷定你都還沒有接觸Kotlin,因為Koltin有一個最重要的優勢就是和Java絕對兼容。

多數據源處理操作符

在RxJava中多數據源處理的操作符很多,但是最經典的就要數merge,contact,zip了。如果對這三個操作符不是很熟悉的話,可以去查看它的使用,當然如果你懶得去看,我也會簡單提一下。merge操作符可以處理多個Observable發送的數據,它是一個非同步操作,不保證數據發送的順序,即有可能出現數據交叉,當一個Observable發送了onError後,未執行的Observable不在繼續執行,直接執行merge的onError方法。

contact操作符執行時一個同步操作,嚴格按照contact中傳入Observable先後執行,即前面的先執行後面的後執行,並且最終發送的數據也是有序的,即第一個Observable的數據發送完畢再發送第二個,依次類推。

zip操作符和contact和merge有了本質的區別,它會將每個Observable個數據項分布對應返回一個Observable再發送,最終發送的數據量與最小數據長度相同。

使用場景分析

假如現在我們有三種商品,有一個查詢商品信息的介面,根據介面可以查詢該商品的價格以及出售地點。商品實體類

代碼

data class Goods(var id:Int,var price: Int, var address: String)

在Kotlin語言中,實體類創建用data class 關鍵詞,我們不需要和Java一樣創建get/set方法,只需一行代碼搞定。

創建模擬網路請求

代碼

object NetRequest {

//模擬網路請求

fun getGoodsObservable(id: Int): Observable {

return Observable.create {

Thread.sleep(Random().nextInt(1000).toLong())

var data = Goods(id, Random().nextInt(20), "地址$")

source.onNext(data)

source.onComplete()

Log.e("getGoodsObservable:", "$")

}

}

}

在上面我們創建了一個單例類,在Kotlin中使用object修飾類時即給我們自動創建了一個單例對象。在每一句代碼結尾我們不需要再和Java一樣寫一個分號「;」來結束,什麼也不用寫。

Observable.create使用的是lambda表達式,在Kotlin語言中是支持lambda表達式的。source 就是ObservableEmitter,所以我們可以調用onNext發送數據。為了更準確的模擬網路請求,使用Thread.sleep隨機的延遲,模擬網路請求的時間。

代碼

fun getGoodsObservable(id: Int): Observable {

return Observable.create {

Thread.sleep(Random().nextInt(1000).toLong())

var data = Goods(id, Random().nextInt(20), "地址$")

source.onNext(data)

source.onComplete()

Log.e("getGoodsObservable:", "$")

}

當然由於subscribe只有一個參數,所以我們也可以這樣寫。也就是省略了source ->,此時it就表示該參數數據。

代碼

return Observable.create {

Thread.sleep(Random().nextInt(1000).toLong())

var data = Goods(id, Random().nextInt(20), "地址$")

it.onNext(data)

it.onComplete()

Log.e("getGoodsObservable:", "$")

}

在java中實現如下

代碼

return Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(@NonNull ObservableEmitter e) throws Exception {

//處理邏輯

}

});

merge

準備好了請求操作,開始使用merge看看執行的效果。

代碼

fun executeMerge() {

Observable.merge(getGoodsObservable(1).subscribeOn(Schedulers.newThread()),

getGoodsObservable(2).subscribeOn(Schedulers.newThread()),

getGoodsObservable(3).subscribeOn(Schedulers.newThread()))

.subscribeOn(Schedulers.newThread())

.observeOn(AndroidSchedulers.mainThread())

.toList()

.subscribe({

Log.e(TAG, it.toString())

}, {

})

}

merge中有三個網路請求操作,並通過subscribeOn(Schedulers.newThread())將網路請求切換到線程中執行,數據都請求成功後,再通過observeOn(AndroidSchedulers.mainThread())切換到主線程請求數據。為了三請求都成功後,我們在更新UI,所以通過toList()將請求的數據轉換成List一塊發送。在上面的subscribe依然使用的lambda表達式,subscribe({},{})中第一個括弧是onSuccess回調,裡面的it是接收到的List數據,第二個括弧是onError回調,it表示異常Throwable對象。

subscribe部分Java代碼

代碼

.subscribe(new Consumer

>() {

@Override

public void accept(@NonNull List goodses) throws Exception {

}

}, new Consumer() {

@Override

public void accept(@NonNull Throwable throwable) throws Exception {

}

});

當然如果你想使用RxJava2中onSubscribe(@NonNull Disposable d) ,你可以這樣使用subscribe

代碼

.subscribe(object : SingleObserver

> {

override fun onSubscribe(d: Disposable?) {

}

override fun onError(e: Throwable?) {

}

override fun onSuccess(t: List?) {

}

})

為了觀察,我們將請求成功的數據顯示在界面上,我們創建一個Button,TextView。

代碼

class MainActivity : AppCompatActivity(), View.OnClickListener {

val TAG = "MainActivity"

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

setSupportActionBar(toolbar)

//加入這句import kotlinx.android.synthetic.main.activity_main.*

//不用再findViewById,可直接使用

merge.setOnClickListener(this)

}

override fun onClick(v: View) {

when (v.id) {

R.id.merge -> {

executeMerge()

}

}

//when 關鍵字和Java中的Switch關鍵詞是類似的,

//只不過它比Java中的Switch強大的多,可以接收任何參數,

//然後判斷使用,也可以如下使用

when (v) {

merge -> {

}

}

}

}

contact

我們點擊執行幾次發現,返回的List的數據並不是按照merge參數的先後順序執行的,它是並發的,最終的順序,是由網路請求的快慢決定的,請求返回數據越快也就表示該數據最早發送,即在List中最靠前。那麼此時出現一個問題,如果我想返回數據的List順序嚴格按照位置的先後順序呢?那此時使用merge的話,是不太現實了。當然前面我們提到contact可以使用。那麼直接將merge更改為contact執行以下試試,

代碼

fun executeContact() {

Observable.concat(getGoodsObservable(1).subscribeOn(Schedulers.newThread()),

getGoodsObservable(2).subscribeOn(Schedulers.newThread()),

getGoodsObservable(3).subscribeOn(Schedulers.newThread()))

.subscribeOn(Schedulers.newThread())

.observeOn(AndroidSchedulers.mainThread())

.toList()

.subscribe({

Log.e(TAG, it.toString())

}, {

})

}

的確,發現無論執行多少次List的數據都能按照contact中Observable順序發送,我們想要的效果可以實現了,不過你會發現,效率太差了,這是同步執行啊,只有第一個請求成功,才會去請求第二個,然後第三個,假如一次請求需要一秒,那三次請求至少三秒啊,不能忍。

zip

鑒於上面兩種方式的利弊,如果我們既想如merge一樣並發執行,又想和contact一樣保證順序,是不是有點強迫症的意思,當然強大的zip就能實現我們想要的效果。如下實現。

代碼

fun executeZip() {

Observable.zip(getGoodsObservable(1),

getGoodsObservable(2),

getGoodsObservable(3),

Function3>

{ goods0, goods1, goods2 ->

val list = ArrayList()

list.add(goods0)

list.add(goods1)

list.add(goods2)

list

}).subscribeOn(Schedulers.newThread())

.observeOn(AndroidSchedulers.mainThread())

.subscribe({

Log.e(TAG, it.toString())

}, {

})

}

既然實現了,那我們運行幾次,發現完美的實現了我們想要的效果,即並發的執行了,也保證了我們請求數據的順序性。

在回調中運用RxJava

在上面我們的單個網路請求是一個同步的請求,如果我們的網路請求封裝了,在線程中請求,請求成功後在主線程中回調,那我們又該如何創建呢使用呢?

先來模擬一個子線程請求網路,請求成功回調數據給主線程。

代碼

fun getGoods(ctx:Context,id: Int,callbacks:(goods:Goods)->Unit): Unit {

ctx.doAsync {

Thread.sleep(Random().nextInt(1000).toLong())

var data = Goods(id, Random().nextInt(20), "地址$")

ctx.runOnUiThread {

callbacks(data)

}

}

}

getGoods傳了三個參數,第一個Context對象,第二個是商品ID,第三個參數是一個函數,(goods:Goods)->Unit表示第三個參數的類型是一個參數為Goods類型並且返回Unit的函數。使用doAsync 模擬非同步請求,請求成功後runOnUiThread 切換到UI線程。然後callbacks(data)將數據回調。這種使用方式比Java中回調優美好用太多了。

接下來就開始在回調成功後創建Observable

代碼

fun getGoodsCallBack(id: Int): Observable {

var subscrbe: ObservableEmitter? = null

var o = Observable.create {

subscrbe = it

}

//Kotlin特性

getGoods(this@MainActivity, id) {

subscrbe?.onNext(it)

}

return o

}

fun executeZipCallBack() {

Observable.zip(getGoodsCallBack(1).subscribeOn(Schedulers.newThread()),

getGoodsCallBack(2).subscribeOn(Schedulers.newThread()),

getGoodsCallBack(3).subscribeOn(Schedulers.newThread()),

Function3>

{ goods0, goods1, goods2 ->

val list = ArrayList()

list.add(goods0)

list.add(goods1)

list.add(goods2)

list

}).subscribeOn(Schedulers.newThread())

.observeOn(AndroidSchedulers.mainThread())

.subscribe({

Log.e(TAG, it.toString())

}, {

})

}

ok,到這裡回調情況下創建使用RxJava也介紹完畢,到此本篇文章就結束了,有問題歡迎指出,內容雜亂,多多擔待,Hava a wonderful day.


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 熵談電商 的精彩文章:

TAG:熵談電商 |

您可能感興趣

去遇見,Free Soul Diving
遇見Dries Van Noton
自從Calvin Klein遇見Raf Simons,一直美麗在線~
JQM Collection 2018 Good Night Kiss 睡衣系列——遇見未知的自己
遇見恐龍Meet Dinosaurs
Sequoia Capital x Mufeeling | 六月,遇見森林之光
遇見你,一路同行,Know how deep I love you
It is good to meet you.茫茫人海,遇見你,真好
瑜伽遇見美食,The sun is soft in May
當Dior遇見Celine:Hedi Slamane成Celine新創意總監
「如果在Brisbane 遇見 Ta」
遇見John Masters Organics 大自然的有機代表作
當 Atom 遇見 VSCode,微軟將對 GitHub做這 6 件事
遇見,預見未來 |Nike LeBron 16 「1-5」 | Xsneaker
遇見「佛系」搖滾:《Find Me Find You:A Story》
當柴犬遇見Louis Vuitton,被萌化了
當山本漢方遇見Hello Kitty
當Zen遇見Vega,AMD 銳龍移動處理器在ideapad 720S上的首秀
cheery bones,遇見不一樣的美
【Me Before You】遇見你之前