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

