kotlin?中的flow?sharedFlow?完整教程
一 sharedFlow是什么
SharedFlow
是 Kotlin 協(xié)程中 Flow
的一種 熱流(Hot Flow),用于在多個訂閱者之間 共享事件或數(shù)據(jù)流。它適合處理 一次性事件(如導(dǎo)航、彈窗、Toast、刷新通知等),而不是持續(xù)狀態(tài)。
? SharedFlow 是什么?
SharedFlow
是 Flow
的一種擴展,具備以下特點:
特性 | 描述 |
---|---|
熱流 | 一旦被觸發(fā),即使沒人監(jiān)聽也會發(fā)出 |
多訂閱者 | 所有活躍訂閱者都能收到事件 |
不保留最新值(除非設(shè)置 replay) | 不像 StateFlow 那樣始終有個當(dāng)前值 |
可配置 buffer 和回放(replay) | 控制事件是否緩存、丟棄或排隊 |
它本質(zhì)上是一個“事件廣播器”。
? 常見使用場景
?? 1. 一次性 UI 事件
- Toast 彈窗
- SnackBar 提示
- 導(dǎo)航跳轉(zhuǎn)
- 關(guān)閉頁面
- 對話框展示/取消
這些事件都是“一次性的”,不需要保存狀態(tài),也不該重復(fù)觸發(fā),因此適合 SharedFlow
。
sealed class UiEvent { data class ShowToast(val message: String) : UiEvent() object NavigateToHome : UiEvent() }
// ViewModel 中 private val _uiEvent = MutableSharedFlow<UiEvent>() val uiEvent = _uiEvent.asSharedFlow() fun loginSuccess() { viewModelScope.launch { _uiEvent.emit(UiEvent.NavigateToHome) } }
// Fragment 中 lifecycleScope.launchWhenStarted { viewModel.uiEvent.collect { event -> when (event) { is UiEvent.ShowToast -> showToast(event.message) is UiEvent.NavigateToHome -> navigate() } } }
?? 2. 流式通知
- 通知其他模塊刷新數(shù)據(jù)
- 數(shù)據(jù)拉取完成通知頁面更新
- ViewModel 向 UI 發(fā)信號
?? 3. 替代 LiveData<Event> 解決重復(fù)消費問題
傳統(tǒng)用 LiveData<Event<T>>
或 SingleLiveEvent
處理一次性事件,代碼復(fù)雜、不優(yōu)雅,而 SharedFlow
是官方推薦的替代方案。
? 在公司項目中,SharedFlow 的典型用法
層 | 使用方式 |
---|---|
ViewModel | 使用 MutableSharedFlow 發(fā)送事件 |
UI(Activity/Fragment) | 使用 collect 監(jiān)聽事件,做 UI 響應(yīng) |
工具類/中間層 | 也可以用于廣播通知、分發(fā)事件 |
示例:登錄成功后跳轉(zhuǎn) + 彈出 Toast
// ViewModel val eventFlow = MutableSharedFlow<UiEvent>() suspend fun login(username: String, pwd: String) { if (doLogin(username, pwd)) { eventFlow.emit(UiEvent.ShowToast("登錄成功")) eventFlow.emit(UiEvent.NavigateHome) } }
? 與其他 Flow 類型的對比
類型 | 是否熱流 | 是否可變 | 是否保留值 | 場景 |
---|---|---|---|---|
Flow | ? 冷流 | ? | ? | 一次性數(shù)據(jù)流 |
SharedFlow | ? 熱流 | ? | ?(可設(shè)置 replay) | 一次性事件廣播 |
StateFlow | ? 熱流 | ? | ?(必須初始值) | 狀態(tài)管理(UI 狀態(tài)、進度等) |
? 總結(jié)一句話:
SharedFlow
= Kotlin 中處理一次性事件的推薦工具,適合在 ViewModel → UI 層傳遞 Toast、導(dǎo)航、彈窗等短暫行為,比 LiveData
更現(xiàn)代、可控。
二 sharedFlow如何處理背壓的?
? 1. SharedFlow 是如何處理被壓的(Backpressure)?
SharedFlow
是 熱流(hot stream),意味著數(shù)據(jù)會立即發(fā)出,而不會像 Flow
那樣等待訂閱者 collect。這也就意味著:
- 如果發(fā)射得太快(比如連續(xù)多次 emit)
- 而訂閱者還沒來得及 collect
- 數(shù)據(jù)就可能被丟棄,或緩存起來等待
這就需要一個“緩存策略”來決定怎么處理這些“來不及處理”的數(shù)據(jù) —— 這就是 SharedFlow 的 buffer 和 溢出策略(onBufferOverflow)。
? 2. replay = 2, extraBufferCapacity = 5 的含義
val sharedFlow = MutableSharedFlow<Int>( replay = 2, extraBufferCapacity = 5 )
這兩者分別控制了兩塊緩存區(qū)域:
參數(shù) | 含義 |
---|---|
replay = 2 | 每個新訂閱者會 立刻收到前 2 條值(即“回放值”) |
extraBufferCapacity = 5 | 除了 replay 緩沖區(qū)之外,還允許臨時緩存 最多 5 條數(shù)據(jù) |
?? 總緩沖區(qū)大小 = replay + extraBufferCapacity
即上面的配置,總共可以緩沖 最多 7 條數(shù)據(jù)。
這意味著在沒有 collect 的情況下,可以最多 emit 7 條數(shù)據(jù)不會失敗或丟失。
? 3. onBufferOverflow = DROP_OLDEST / DROP_LATEST / SUSPEND 是什么?
這是控制當(dāng) 緩沖區(qū)已滿時,繼續(xù) emit 會怎么處理的策略。
支持的策略:
策略名 | 解釋 |
---|---|
DROP_OLDEST | 丟掉最早 emit 的一條數(shù)據(jù)(先進先出) |
DROP_LATEST | 丟掉新發(fā)射的數(shù)據(jù)(調(diào)用的 emit) |
SUSPEND (默認) | 掛起 emit 調(diào)用,直到 buffer 有空間(安全但可能阻塞) |
示例說明:
val flow = MutableSharedFlow<Int>( replay = 1, extraBufferCapacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST )
此時總 buffer 是 3 條:
- 如果連續(xù) emit 第 1、2、3 條 → 都能進 buffer。
- 如果 emit 第 4 條時還沒人 collect → buffer 滿了。
DROP_OLDEST
策略:會把 第 1 條值移除,保留 2、3、4。
?? emit() 和 tryEmit() 的區(qū)別:
emit()
是 掛起函數(shù),可能會suspend
(如果 buffer 滿且策略是SUSPEND
)。tryEmit()
是 非掛起,返回true/false
表示是否成功發(fā)射。
? 總結(jié)一句話:
配置項 | 意義 |
---|---|
replay | 新訂閱者能收到多少“歷史值” |
extraBufferCapacity | 在未 collect 情況下,能暫存多少新值 |
onBufferOverflow | 當(dāng)緩存已滿,是否丟老的、丟新的,或掛起等候 |
總緩存 | replay + extraBufferCapacity 條數(shù)據(jù) |
到此這篇關(guān)于kotlin 中的flow sharedFlow 完整教程的文章就介紹到這了,更多相關(guān)kotlin sharedFlow內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Ubuntu中為Android實現(xiàn)Application Frameworks層增加硬件訪問服務(wù)
本文主要介紹Android實現(xiàn) Application Frameworks層增加硬件訪問服務(wù),這里對實現(xiàn)增加硬件訪問服務(wù)的功能做出了詳細的工作流程,并提供示例代碼,有需要的小伙伴參考下2016-08-08Android通過Handler與AsyncTask兩種方式動態(tài)更新ListView(附源碼)
這篇文章主要介紹了Android通過Handler與AsyncTask兩種方式動態(tài)更新ListView的方法,結(jié)合實例形式分析了ListView動態(tài)更新的常用技巧,并附上完整實例源碼供讀者下載,需要的朋友可以參考下2015-12-12Android編程實現(xiàn)手機自帶內(nèi)部存儲路徑的獲取方法
這篇文章主要介紹了Android編程實現(xiàn)手機自帶內(nèi)部存儲路徑的獲取方法,涉及Android針對掛載點信息的獲取技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11Android利用DownloadManager實現(xiàn)文件下載
這篇文章主要為大家詳細介紹了Android利用DownloadManager實現(xiàn)文件下載,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08