Kotlin StateFlow單數(shù)據(jù)更新熱流設計與使用介紹
一.StateFlow的設計
StateFlow是一種單數(shù)據(jù)更新的熱流,通過emit方法更新StateFlow的數(shù)據(jù),通過value屬性可以獲取當前的數(shù)據(jù)。在StateFlow中,核心接口的繼承關系如下圖所示:
1.StateFlow接口
StateFlow接口繼承自SharedFlow接口,代碼如下:
public interface StateFlow<out T> : SharedFlow<T> { // 當前的數(shù)據(jù) public val value: T }
- 訂閱過程:在StateFlow中,每個FlowCollecter類型的對象都被稱為訂閱者。調(diào)用StateFlow類型對象的collect方法會觸發(fā)訂閱。正常情況下,訂閱不會自動結(jié)束,但訂閱者可以取消訂閱,當訂閱者所在的協(xié)程被取消時,訂閱過程就會取消。
- 冷流轉(zhuǎn)換熱流:對于一個冷流,可以通過調(diào)用stateIn方法,轉(zhuǎn)換為一個單數(shù)據(jù)更新的熱流。
- 相等判定:在StateFlow中,通過Any#equals方法來判斷前后兩個數(shù)據(jù)是否相等。當前后兩個數(shù)據(jù)相等時,數(shù)據(jù)不會被更新,訂閱者也不會處理。
- 數(shù)據(jù)緩存:StateFlow必須要有一個初始值。當新訂閱者出現(xiàn)時,StateFlow會將最新的數(shù)據(jù)發(fā)射給訂閱者。StateFlow只保留最后發(fā)射的數(shù)據(jù),除此之外不會緩存任何其他的數(shù)據(jù)。同時,StateFlow不支持resetReplayCache方法。
- StateFlow并發(fā): StateFlow中所有的方法都是線程安全的,并且可以在多協(xié)程并發(fā)的場景中使用且不必額外加鎖。
- 操作符使用:對StateFlow使用flowOn操作符、conflate操作符、參數(shù)為CONFLATED或RENDEZVOUS的buffer操作符、cancellable操作符是無效的。
- 使用場景:使用StateFlow作為數(shù)據(jù)模型,可以表示任何狀態(tài)。
- StateFlow與SharedFlow的區(qū)別:StateFlow是SharedFlow的一種特定方向的、高性能的、高效的實現(xiàn),廣泛的用于單狀態(tài)變化的場景,所有與SharedFlow相關基本規(guī)則、約束、操作符都適用于StateFlow。當使用如下的參數(shù)創(chuàng)建SharedFlow對象,并對其使用distinctUntilChanged操作符,可以得到一個與StateFlow行為相同的SharedFlow對象:
// StateFlow val stateFlow = MutableStateFlow(initialValue) // 與StateFlow行為相同的SharedFlow // 注意參數(shù) val sharedFlow = MutableSharedFlow( replay = 1, extraBufferCapacity = 0, onBufferOverflow = BufferOverflow.DROP_OLDEST) // 設置初始值 sharedFlow.tryEmit(initialValue) // distinctUntilChanged方法,只有當前后發(fā)射的兩個數(shù)據(jù)不同時才會將數(shù)據(jù)向下游發(fā)射 val state = sharedFlow.distinctUntilChanged()
StateFlow與ConflatedBroadcastChannel的區(qū)別:從概念上講,StateFlow與ConflatedBroadcastChannel很相似,但二者也有很大的差別,推薦使用StateFlow,StateFlow設計的目的就是要在未來替代ConflatedBroadcastChannel:
- StateFlow更簡單,不需要實現(xiàn)一堆與Channel相關的接口。
- StateFlow始終持有一個數(shù)據(jù),并且無論在任何時間都可以安全的通過value屬性獲取。
- StateFlow清楚地劃分了只讀的StateFlow和可讀可寫的StateFlow。
- StateFlow對前后數(shù)據(jù)的比較是與distinctUntilChanged操作符類似的,而ConflatedBroadcastChannel對數(shù)據(jù)進行相等比較是基于標識引用。
- StateFlow不能關閉,也不能表示失敗,因此如果需要,所有的錯誤與完成信號都應該具體化。
2. MutableStateFlow接口
MutableStateFlow接口繼承自MutableSharedFlow接口與StateFlow接口,并在此基礎上定義了一個新方法compareAndSet,代碼如下:
public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> { // 當前數(shù)據(jù) public override var value: T // 通過CAS的方式,更新value // 如果except與value相等,則將value更新為update,并返回true // 如果except與value不相等,不做任何操作,直接返回false // 如果except、value、update同時相等,不做任何操作,直接返回true public fun compareAndSet(expect: T, update: T): Boolean }
二.StateFlow的使用
1.MutableStateFlow方法
在協(xié)程中,可以通過調(diào)用MutableStateFlow方法創(chuàng)建一個MutableStateFlow接口指向的對象,代碼如下:
public fun <T> MutableStateFlow(value: T): MutableStateFlow<T> { ... }
通過MutableStateFlow方法可以創(chuàng)建一個類型為MutableStateFlow的對象,需要提供一個參數(shù)value,作為初始值。
在并發(fā)場景下調(diào)用emit方法時,會使StateFlow的數(shù)據(jù)快速更新,對于處理數(shù)據(jù)慢的訂閱者,將會跳過這些快速更新的數(shù)據(jù),但當訂閱者需要處理數(shù)據(jù)時,獲取的一定是最新更新的數(shù)據(jù)。
2.使用示例
代碼如下:
private suspend fun test() { // 創(chuàng)建一個熱流,初始值為1 val flow = MutableStateFlow(1) // 將MutableStateFlow對象轉(zhuǎn)換為StateFlow對象 // StateFlow對象不能調(diào)用emit方法,因此只能用于接收 val onlyReadFlow = flow.asStateFlow() // 接收者1 // 啟動一個新的協(xié)程 GlobalScope.launch { // 觸發(fā)并處理接收的數(shù)據(jù) onlyReadFlow.collect { Log.d("liduozuishuai", "test1: $it") } } // 接收者2 // 啟動一個新協(xié)程 GlobalScope.launch { // 訂閱監(jiān)聽,當collect方法觸發(fā)訂閱時,會首先會調(diào)onSubscription方法 onlyReadFlow.onSubscription { Log.d("liduozuishuai", "test2: ") // 發(fā)射數(shù)據(jù):2 // 向下游發(fā)射數(shù)據(jù):2,其他接收者收不到 emit(2) }.onEach { // 處理接收的數(shù)據(jù) Log.d("liduozuishuai", "test2: $it") }.collect() } // 發(fā)送數(shù)據(jù):3,多次發(fā)送 GlobalScope.launch { flow.emit(3) flow.emit(3) flow.compareAndSet(3, 3) } }
對于上面的示例,接收者1會依次打印出:1、3,接收者2會依次打印出2、3。接收者2由于在處理onSubscription方法發(fā)射的數(shù)據(jù)2時,MutableStateFlow對象內(nèi)部的數(shù)據(jù)1變成了數(shù)據(jù)3,因此在處理完數(shù)據(jù)2后,直接處理數(shù)據(jù)3。
到此這篇關于Kotlin StateFlow單數(shù)據(jù)更新熱流設計與使用介紹的文章就介紹到這了,更多相關Kotlin StateFlow內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android實現(xiàn)網(wǎng)絡加載圖片點擊大圖后瀏覽可縮放
這篇文章主要為大家詳細介紹了Android實現(xiàn)網(wǎng)絡加載圖片點擊大圖后瀏覽可縮放,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12flutter升級3.7.3報錯Unable?to?find?bundled?Java?version解決
這篇文章主要介紹了flutter升級3.7.3報錯Unable?to?find?bundled?Java?version解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加2023-02-02Android使用BottomTabBar實現(xiàn)底部導航頁效果
這篇文章主要介紹了Android使用BottomTabBar實現(xiàn)底部導航頁效果,本文通過實例代碼結(jié)合文字說明的形式給大家介紹的非常詳細,需要的朋友參考下吧2018-03-03Android listview與adapter詳解及實例代碼
本文主要介紹Android listview與adapter的知識詳解,這里整理了相關資料及實現(xiàn)代碼和實現(xiàn)效果圖,有興趣的小伙伴可以參考下2016-09-09