Kotlin中?StateFlow?或?SharedFlow?的區(qū)別解析
StateFlow
和 SharedFlow
是 Kotlin 協(xié)程(Coroutines) 提供的兩種 響應(yīng)式數(shù)據(jù)流(Reactive Streams),用于在應(yīng)用程序中處理異步數(shù)據(jù)流,類似于 RxJava 的 Observable
或 Flowable
,但更輕量且與 Kotlin 協(xié)程深度集成。
1. StateFlow(狀態(tài)流)
StateFlow
是一種 熱流(Hot Flow),它會(huì)存儲(chǔ)當(dāng)前的狀態(tài)值,并在狀態(tài)變化時(shí)通知所有訂閱者。
特點(diǎn)
- 必須有初始值(不能為空)。
- 只保留最新的值(新訂閱者會(huì)立即收到當(dāng)前值)。
- 是
SharedFlow
的特殊情況(相當(dāng)于replay=1
的SharedFlow
)。 - 適用于 UI 狀態(tài)管理(如
ViewModel
暴露 UI 狀態(tài))。
示例
// 定義 StateFlow(通常在 ViewModel 中) private val _counterState = MutableStateFlow(0) // 初始值 0 val counterState: StateFlow<Int> = _counterState.asStateFlow() // 更新值 fun increment() { _counterState.value++ // 自動(dòng)通知所有訂閱者 } // 在 Activity/Fragment 中監(jiān)聽 lifecycleScope.launch { viewModel.counterState.collect { value -> textView.text = "Count: $value" } }
2. SharedFlow(共享流)
SharedFlow
也是一種 熱流,但它不存儲(chǔ)狀態(tài),而是用于 廣播事件(如一次性事件、通知等)。
特點(diǎn)
- 沒有初始值(可以發(fā)送任意數(shù)量的數(shù)據(jù))。
- 可以配置緩存大小(
replay
控制新訂閱者能收到多少歷史數(shù)據(jù))。 - 適用于事件總線、通知等場(chǎng)景(如 Toast 消息、導(dǎo)航事件)。
示例
// 定義 SharedFlow(通常在 ViewModel 中) private val _toastEvent = MutableSharedFlow<String>() // 無初始值 val toastEvent: SharedFlow<String> = _toastEvent.asSharedFlow() // 發(fā)送事件 fun showToast(message: String) { viewModelScope.launch { _toastEvent.emit(message) // 發(fā)送事件 } } // 在 Activity/Fragment 中監(jiān)聽 lifecycleScope.launch { viewModel.toastEvent.collect { message -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } }
StateFlow
vs SharedFlow
特性 | StateFlow | SharedFlow |
---|---|---|
初始值 | ? 必須有 | ? 不需要 |
緩存歷史數(shù)據(jù) | 僅最新值 | 可配置 (replay ) |
適用場(chǎng)景 | UI 狀態(tài)管理(如 LiveData 替代) | 事件總線、通知 |
是否熱流 | ? 是 | ? 是 |
線程安全 | ? 是(協(xié)程作用域內(nèi)) | ? 是 |
因此,以下面這段代碼舉例:
/** * 應(yīng)用中心數(shù)據(jù)變化,更新應(yīng)用中心小組件的顯示 */ private fun WidgetSelectorViewModel.observerAppList() = coroutineScope.launch { appWidgets.onEach { list -> Log.d(TAG, "observerAppList setDataList") gridAdapterApp.setDataList(list) appItemBinding?.groupNoData?.isVisible = list.isEmpty() }.launchIn(coroutineScope) }
功能總結(jié):
這段代碼的主要作用是監(jiān)聽?wèi)?yīng)用小組件列表(appWidgets)的變化,每當(dāng)列表更新時(shí):
將新列表設(shè)置給網(wǎng)格適配器(gridAdapterApp)以更新UI
根據(jù)列表是否為空來顯示或隱藏"無數(shù)據(jù)"的提示
所有這些操作都在協(xié)程中異步執(zhí)行
這是一種典型的響應(yīng)式編程模式,通過觀察數(shù)據(jù)流來自動(dòng)更新UI,避免了手動(dòng)刷新數(shù)據(jù)的需要。
首先是函數(shù)定義:
private fun WidgetSelectorViewModel.observerAppList() = coroutineScope.launch {
- 這是一個(gè) WidgetSelectorViewModel 的擴(kuò)展函數(shù)
- 函數(shù)是私有的(private)
- 返回一個(gè)協(xié)程啟動(dòng)器(launch)
- 函數(shù)名為 observerAppList(),表示它用于觀察應(yīng)用列表
其次是函數(shù)體:
appWidgets.onEach { list -> gridAdapterApp.setDataList(list) appItemBinding?.groupNoData?.isVisible = list.isEmpty() }.launchIn(coroutineScope)
appWidgets
可能是一個(gè)StateFlow
或SharedFlow
(取決于它的定義)。onEach
會(huì)在每次數(shù)據(jù)變化時(shí)執(zhí)行,更新 UI。launchIn(coroutineScope)
表示在指定的協(xié)程作用域內(nèi)啟動(dòng)這個(gè)流。
總結(jié)
StateFlow
→ 用于 UI 狀態(tài)管理(如LiveData
的替代)。SharedFlow
→ 用于 事件通知(如 Toast、導(dǎo)航事件)。- 兩者都是 熱流,即使沒有訂閱者也會(huì)發(fā)送數(shù)據(jù)。
- 通常結(jié)合
ViewModel
+collect
使用,實(shí)現(xiàn)響應(yīng)式 UI 更新。
如果你的 appWidgets
是一個(gè)應(yīng)用列表的狀態(tài),那它更適合用 StateFlow
;如果是臨時(shí)事件(如刷新完成通知),則更適合 SharedFlow
。
到此這篇關(guān)于Kotlin中 StateFlow 或 SharedFlow 的區(qū)別的文章就介紹到這了,更多相關(guān)Kotlin StateFlow 或 SharedFlow 的區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中HTTP請(qǐng)求不通的原因級(jí)解決方法
HTTP 請(qǐng)求是指從客戶端到服務(wù)器的請(qǐng)求消息,對(duì)于一個(gè) Spring Boot 項(xiàng)目而言,服務(wù)器就是 Spring Boot,客戶端就是用戶本地的瀏覽器,但是會(huì)遇到SpringBoot HTTP請(qǐng)求不通的問題,本文介紹了一些常見問題及解決方法,需要的朋友可以參考下2025-02-02JAVA實(shí)現(xiàn)PDF轉(zhuǎn)HTML文檔的示例代碼
本文是基于PDF文檔轉(zhuǎn)PNG圖片,然后進(jìn)行圖片拼接,拼接后的圖片轉(zhuǎn)為base64字符串,然后拼接html文檔寫入html文件實(shí)現(xiàn)PDF文檔轉(zhuǎn)HTML文檔,感興趣的可以了解一下2021-05-05如何利用Spring?MVC實(shí)現(xiàn)RESTful風(fēng)格
這篇文章主要介紹了如何利用Spring?MVC實(shí)現(xiàn)RESTful風(fēng)格,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02springBoot使用openfeign來遠(yuǎn)程調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了springBoot使用openfeign來遠(yuǎn)程調(diào)用的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03spring中REST和RESTful的區(qū)別以及基本實(shí)現(xiàn)
本文主要介紹了spring中REST和RESTful的區(qū)別以及基本實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04詳解Springboot整合Dubbo之代碼集成和發(fā)布
本篇文章主要介紹了Springboot整合Dubbo之代碼集成和發(fā)布,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12Spring-Boot 集成Solr客戶端的詳細(xì)步驟
本篇文章主要介紹了Spring-Boot 集成Solr客戶端的詳細(xì)步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11eclipse啟動(dòng)tomcat無法訪問的解決方法
這篇文章介紹了eclipse啟動(dòng)tomcat無法訪問的解決方法,有需要的朋友可以參考一下2013-10-10