網站首頁 編程語言 正文
Kotlin中StateFlow的使用
StateFlow 是 Flow 的實現,是一個特殊的流,默認的 Flow 是冷流,而StateFlow 是熱流,和 LiveData 比較類似。關于冷熱流后面一期 SharedFlow 會詳細說明。
使用 StateFlow 替代 LiveData 應該是目前很多開發者的呼吁了,確實 LiveData 的功能 StateFlow 都能實現,可以說是 LiveData 的升級版。
StateFlow的特點
- 它始終是有值的。
- 它的值是唯一的。
- 它允許被多個觀察者共用 (因此是共享的數據流)。
- 它永遠只會把最新的值重現給訂閱者,這與活躍觀察者的數量是無關的。
官方推薦當暴露 UI 的狀態給視圖時,應該使用 StateFlow。這是一種安全和高效的觀察者,專門用于容納 UI 狀態。
一、StateFlow的使用
方式一,我們自己 new 出來
一般我們再ViewModel中定義讀寫分類的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")
}
}
}
方式二,通過一個 冷流 Flow 轉換為 StateFlow
val stateFlow = flowOf(1, 2, 3).stateIn(
scope = lifecycleScope,
// started = WhileSubscribed(5000, 1000),
// started = Eagerly,
started = Lazily,
initialValue = 1
)
lifecycleScope.launch {
stateFlow.collect {
}
}
幾個重要參數的說明如下
- scope 共享開始時所在的協程作用域范圍
- started 控制共享的開始和結束的策略
- Lazily: 當首個訂閱者出現時開始,在 scope 指定的作用域被結束時終止。
- Eagerly: 立即開始,而在 scope 指定的作用域被結束時終止。
- WhileSubscribed能夠指定當前不有訂閱者后,多少時間取消上游數據和能夠指定多少時間后,緩存中的數據被丟失,回復稱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有什么缺點?
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中觸發與接收事件
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中同樣的是都能使用。那么它們有哪些差異呢?
它們相同的地方:
- 僅持有單個且最新的數據
- 自動取消訂閱
- 提供「可讀可寫」和「僅可讀」兩個版本收縮權限
- 配合 DataBinding 實現「雙向綁定」
相比StateFlow ,LiveData的確定:
- LiveData在某些特定的場景下會丟失數據
- LiveData 只能在主線程不能方便地支持異步化
- LiveData 的數據變換能力遠遠不如 Flow
- LiveData 粘性問題解決需要額外擴展
- LiveData 多數據源的合流能力遠遠不如 Flow
- LiveData 默認不支持防抖,值沒有變化也會通知
這么慘,那我們開發是不是要放棄LiveData了?
恰恰不是!
如果大家全部是Koltin代碼開發,那么是可以用Flow,這是基于Kotlin代碼,基于協程實現的,但是現在很多項目還是 Java 語言開發的。那么LiveData還是很香的。
其二是LiveData的學習成本與 協程、Flow 的學習成本不可同日而語,開發項目是整個團隊的事情,不能說你一個人會一個人用,目前LiveData的簡單學習成本是很有優勢的。
只是我們需要在一些特定的場景慎重使用postValue,比如數據比較秘籍的場景,我們盡量使用setValue方法。
總結
如果大家的項目的語言是 Kotlin ,并且小組成員都會 Flow 。那么我推薦你們使用StateFlow 替代LiveData 。如果不是,那么 LiveData 是你最好的選擇。
谷歌也只是推薦使用Flow替代LiveData。但是并沒有說打算放棄 LiveData 。并且 LiveData 與 StateFlow 都有各自的使用場景,不需要擔心 LiveData的 使用。
本文我們只是簡單的對比,關于StateFlow 與 SharedFlow 和LiveData 三者的差異與選擇,后面等SharedFlow那一期詳細的講解。
原文鏈接:https://juejin.cn/post/7127082531358244900
相關推薦
- 2022-09-10 nginx?Rewrite重寫地址的實現_nginx
- 2022-04-09 SpringBoot設置CorsFilter過濾器解決跨域問題
- 2022-05-13 分布式架構Redis中有哪些數據結構及底層實現原理_Redis
- 2022-07-13 Stream的源碼簡單解析
- 2022-11-08 Go讀取文件與寫入文件的三種方法操作指南_Golang
- 2022-08-10 Qt利用DOM類實現讀取xml文件_C 語言
- 2023-07-26 vscode中配置代碼片段
- 2022-12-04 Nginx?禁止直接訪問目錄或文件的操作方法_nginx
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支