Kotlin Flow常用封裝類StateFlow使用詳解
Kotlin中StateFlow的使用
StateFlow 是 Flow 的實(shí)現(xiàn),是一個(gè)特殊的流,默認(rèn)的 Flow 是冷流,而StateFlow 是熱流,和 LiveData 比較類似。關(guān)于冷熱流后面一期 SharedFlow 會(huì)詳細(xì)說明。
使用 StateFlow 替代 LiveData 應(yīng)該是目前很多開發(fā)者的呼吁了,確實(shí) LiveData 的功能 StateFlow 都能實(shí)現(xiàn),可以說是 LiveData 的升級(jí)版。
StateFlow的特點(diǎn)
- 它始終是有值的。
- 它的值是唯一的。
- 它允許被多個(gè)觀察者共用 (因此是共享的數(shù)據(jù)流)。
- 它永遠(yuǎn)只會(huì)把最新的值重現(xiàn)給訂閱者,這與活躍觀察者的數(shù)量是無關(guān)的。
官方推薦當(dāng)暴露 UI 的狀態(tài)給視圖時(shí),應(yīng)該使用 StateFlow。這是一種安全和高效的觀察者,專門用于容納 UI 狀態(tài)。
一、StateFlow的使用
方式一,我們自己 new 出來
一般我們?cè)賄iewModel中定義讀寫分類的StateFlow
@HiltViewModel
class Demo4ViewModel @Inject constructor(
val savedState: SavedStateHandle
) : BaseViewModel() {
private val _searchFlow = MutableStateFlow("")
val searchFlow: StateFlow<String> = _searchFlow
fun changeSearch(keyword: String) {
_searchFlow.value = keyword
}
}
在Activity中我們就可以像類似 LiveData 一樣的使用 StateFlow
private fun testflow() {
mViewModel.changeSearch("key")
}
override fun startObserve() {
lifecycleScope.launchWhenCreated {
mViewModel.searchFlow.collect {
YYLogUtils.w("value $it")
}
}
}
方式二,通過一個(gè) 冷流 Flow 轉(zhuǎn)換為 StateFlow
val stateFlow = flowOf(1, 2, 3).stateIn(
scope = lifecycleScope,
// started = WhileSubscribed(5000, 1000),
// started = Eagerly,
started = Lazily,
initialValue = 1
)
lifecycleScope.launch {
stateFlow.collect {
}
}
幾個(gè)重要參數(shù)的說明如下
- scope 共享開始時(shí)所在的協(xié)程作用域范圍
- started 控制共享的開始和結(jié)束的策略
- Lazily: 當(dāng)首個(gè)訂閱者出現(xiàn)時(shí)開始,在 scope 指定的作用域被結(jié)束時(shí)終止。
- Eagerly: 立即開始,而在 scope 指定的作用域被結(jié)束時(shí)終止。
- WhileSubscribed能夠指定當(dāng)前不有訂閱者后,多少時(shí)間取消上游數(shù)據(jù)和能夠指定多少時(shí)間后,緩存中的數(shù)據(jù)被丟失,回復(fù)稱initialValue的值。
- initialValue 初始值
二、替代LiveData
不管是普通的 ViewModel 觀察訂閱模式,在Activity中訂閱,還是DataBinding的模式,我們都可以使用StateFlow來代替ViewModel
val withdrawMethod = MutableStateFlow(0)
<ImageView
android:id="@+id/iv_giro_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/d_15dp"
android:src="@drawable/pay_method_checked"
android:visibility="gone"
binding:isVisibleGone="@{viewModel.withdrawMethod == 1}" />
為什么我們需要用StateFlow來代替LiveData,或者說LiveData有什么缺點(diǎn)?
LiveData vs Flow
先上代碼,看看它們的用法與差異
ViewModel的代碼
@HiltViewModel
class Demo4ViewModel @Inject constructor(
val savedState: SavedStateHandle
) : BaseViewModel() {
private val _searchLD = MutableLiveData<String>()
val searchLD: LiveData<String> = _searchLD
private val _searchFlow = MutableStateFlow("")
val searchFlow: StateFlow<String> = _searchFlow
fun changeSearch(keyword: String) {
_searchFlow.value = keyword
_searchLD.value = keyword
}
}
Activity中觸發(fā)與接收事件
private fun testflow() {
mViewModel.changeSearch("key")
}
override fun startObserve() {
mViewModel.searchLD.observe(this){
YYLogUtils.w("value $it")
}
lifecycleScope.launchWhenCreated {
mViewModel.searchFlow.collect {
YYLogUtils.w("value $it")
}
}
}
可以看到基本的使用幾乎是沒有差異,在DataBinding中同樣的是都能使用。那么它們有哪些差異呢?
它們相同的地方:
- 僅持有單個(gè)且最新的數(shù)據(jù)
- 自動(dòng)取消訂閱
- 提供「可讀可寫」和「僅可讀」兩個(gè)版本收縮權(quán)限
- 配合 DataBinding 實(shí)現(xiàn)「雙向綁定」
相比StateFlow ,LiveData的確定:
- LiveData在某些特定的場(chǎng)景下會(huì)丟失數(shù)據(jù)
- LiveData 只能在主線程不能方便地支持異步化
- LiveData 的數(shù)據(jù)變換能力遠(yuǎn)遠(yuǎn)不如 Flow
- LiveData 粘性問題解決需要額外擴(kuò)展
- LiveData 多數(shù)據(jù)源的合流能力遠(yuǎn)遠(yuǎn)不如 Flow
- LiveData 默認(rèn)不支持防抖,值沒有變化也會(huì)通知
這么慘,那我們開發(fā)是不是要放棄LiveData了?
恰恰不是!
如果大家全部是Koltin代碼開發(fā),那么是可以用Flow,這是基于Kotlin代碼,基于協(xié)程實(shí)現(xiàn)的,但是現(xiàn)在很多項(xiàng)目還是 Java 語(yǔ)言開發(fā)的。那么LiveData還是很香的。
其二是LiveData的學(xué)習(xí)成本與 協(xié)程、Flow 的學(xué)習(xí)成本不可同日而語(yǔ),開發(fā)項(xiàng)目是整個(gè)團(tuán)隊(duì)的事情,不能說你一個(gè)人會(huì)一個(gè)人用,目前LiveData的簡(jiǎn)單學(xué)習(xí)成本是很有優(yōu)勢(shì)的。
只是我們需要在一些特定的場(chǎng)景慎重使用postValue,比如數(shù)據(jù)比較秘籍的場(chǎng)景,我們盡量使用setValue方法。
總結(jié)
如果大家的項(xiàng)目的語(yǔ)言是 Kotlin ,并且小組成員都會(huì) Flow 。那么我推薦你們使用StateFlow 替代LiveData 。如果不是,那么 LiveData 是你最好的選擇。
谷歌也只是推薦使用Flow替代LiveData。但是并沒有說打算放棄 LiveData 。并且 LiveData 與 StateFlow 都有各自的使用場(chǎng)景,不需要擔(dān)心 LiveData的 使用。
本文我們只是簡(jiǎn)單的對(duì)比,關(guān)于StateFlow 與 SharedFlow 和LiveData 三者的差異與選擇,后面等SharedFlow那一期詳細(xì)的講解。
為什么很多東西都要等SharedFlow,是因?yàn)?SharedFlow 是 StateFlow 的基礎(chǔ),StateFlow 像是 SharedFlow 的‘青春版’。很多東西需要講完 SharedFlow 才能把知識(shí)點(diǎn)串起來,更多關(guān)于Kotlin Flow封裝類StateFlow的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android模仿實(shí)現(xiàn)微博詳情頁(yè)滑動(dòng)固定頂部欄的效果實(shí)例
這篇文章主要給大家介紹了關(guān)于利用Android模仿實(shí)現(xiàn)微博詳情頁(yè)滑動(dòng)固定頂部欄效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11
android多媒體音樂(MediaPlayer)播放器制作代碼
這篇文章主要為大家詳細(xì)介紹了android多媒體音樂(MediaPlayer)播放器的制作相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
Android延遲實(shí)現(xiàn)的幾種解決方法及原理分析
這篇文章主要給大家介紹了關(guān)于Android延遲實(shí)現(xiàn)的幾種解決方法以及其中的原理分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
Android4.0平板開發(fā)之隱藏底部任務(wù)欄的方法
這篇文章主要介紹了Android4.0平板開發(fā)之隱藏底部任務(wù)欄的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android隱藏于顯示底部任務(wù)欄的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
android遞歸壓縮上傳多張圖片到七牛的實(shí)例代碼
本篇文章主要介紹了android遞歸壓縮上傳多張圖片到七牛的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android性能優(yōu)化之ViewPagers?+?Fragment緩存優(yōu)化
這篇文章主要介紹了Android性能優(yōu)化之ViewPagers+Fragment緩存優(yōu)化,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
Android實(shí)現(xiàn)手機(jī)震動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)手機(jī)震動(dòng)效果的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02

