擁抱 Kotlin Flow

1. 引言

Kotlin Flow 是 Kotlin 協程生態中處理異步數據流的核心工具,它提供了一種聲明式、輕量級且與協程深度集成的響應式編程模型。與傳統的 RxJava 相比,Flow 更簡潔、更易于維護,尤其在 Android 開發中已成為主流選擇。本文將從基礎概念到高級特性全面解析 Flow,結合實戰案例幫助讀者深入掌握這一強大工具。

2. Flow 基礎概念

2.1 冷流與熱流

冷流(Cold Flow):只有在被收集(collect)時才會開始執行,每個收集器獨立運行。例如:

// 創建冷流,使用flow構建器,只有在被收集時才會發射數據val coldFlow = flow {emit(1) // 收集時執行emit(2) // 收集時執行}

冷流特性

按需觸發:類似「點播電影」,只有訂閱時才開始播放

獨立副本:每個訂閱者觸發獨立的數據流(如多次collect會重新執行flow塊)

適用場景:網絡請求、數據庫查詢等一次性任務

熱流(Hot Flow):創建后立即開始發射數據,多個收集器共享數據流。例如 StateFlowSharedFlow

// 創建熱流(SharedFlow),創建后立即開始發射數據val hotFlow = MutableSharedFlow<Int>()//啟動協程持續發射數據(即使沒有訂閱者)launch {(0..2).forEach {delay(1000)hotFlow.emit(it) // 發射0,1,2(間隔1秒)}}

熱流特性

主動發射:類似「直播電視」,數據持續生產

共享數據源:多個訂閱者共享最新數據

適用場景:實時狀態同步(如 UI 更新)、全局事件通知

冷熱流對比表

特性冷流熱流
數據發射時機訂閱時觸發創建后持續發射
訂閱者關系獨立執行共享數據流
典型實現flow{}asFlow()StateFlowSharedFlow
適用場景單次任務(網絡請求)實時數據(傳感器、WebSocket)

2.2 核心組件

生產者:通過 emit 發送數據。

操作符:對流進行轉換、過濾、合并等處理。

消費者:通過 collect 等終端操作符處理數據。

數據流模型

//生產者flow {emit("數據1") // 發送數據emit("數據2")}//操作符鏈.map { it.toUpperCase() } // 轉換操作符.filter { it.contains("2") } // 過濾操作符//消費者.collect { println(it) } // 終端操作符

3. Flow 的創建與消費

3.1 創建方式

flowOf:快速創建固定數據的流。

//創建包含1、2、3的流,底層使用channel實現val flow = flowOf(1, 2, 3)

asFlow:將集合轉換為流。

//將列表轉換為流,支持惰性處理val list = listOf(1, 2, 3)val flow = list.asFlow()

callbackFlow:處理回調式異步操作。

//創建callbackFlow處理網絡回調val callbackFlow = callbackFlow<String> {val listener = object : Listener {override fun onData(data: String) {trySend(data) // 安全發射數據}}registerListener(listener) // 注冊監聽awaitClose { unregisterListener(listener) } // 關閉時取消監聽}

3.2 消費方式

collect:收集所有數據。

//在協程中收集數據,每個值觸發打印flow.collect { value -> println(value) }

first:獲取第一個元素。

//獲取第一個元素,流為空時拋出異常val firstValue = flow.first()

4. 核心操作符詳解

4.1 轉換操作符

map:轉換元素類型。

//將整數流轉換為字符串流flow.map { it.toString() }

transform:自定義轉換邏輯,可發射多個值。

//對每個元素發射兩次(乘2和加1)flow.transform {emit(it * 2)emit(it + 1)}

4.2 過濾操作符

filter:保留符合條件的元素。

//過濾偶數flow.filter { it % 2 == 0 }

distinctUntilChanged:去重連續重復元素。

//去除連續重復元素(如[1,1,2,2]→[1,2])flow.distinctUntilChanged()

4.3 組合操作符

zip:合并兩個流。

//合并兩個流,對應位置元素相加flow1.zip(flow2) { a, b -> a + b }

combine:合并多個流的最新值。

//合并溫度和濕度流,計算舒適度指數combine(tempFlow, humidityFlow) { t, h ->&#x20;(t - 18) * 0.7 + (h - 60) * 0.3&#x20;}

4.4 背壓處理操作符

buffer:緩存數據,避免生產者阻塞。

//設置緩沖區大小為10,溢出時掛起生產者flow.buffer(10, BufferOverflow.SUSPEND)

conflate:丟棄中間值,僅處理最新值。

//實時位置更新時跳過中間幀flow.conflate()

4.5 高級操作符

flatMapLatest:處理最新流,取消未完成操作。

//搜索輸入時取消舊請求searchFlow.flatMapLatest { query ->searchApi.fetch(query) // 新請求到達時取消舊請求}

debounce:防抖處理(如搜索框輸入)。

//輸入停止1秒后觸發搜索searchFlow.debounce(1000)

5. 背壓管理

5.1 背壓概念

當生產者速度超過消費者時,需通過背壓策略處理數據積壓。Flow 提供以下策略:

buffer:使用緩沖區存儲數據。

conflate:丟棄舊值,保留最新值。

collectLatest:取消未完成的操作,處理最新值。

5.2 示例

//生產者每秒發射1個數據flow {(1..5).forEach {emit(it)delay(100) // 生產間隔100ms}}.collect {delay(200) // 消費間隔200ms,導致背壓println(it)}//使用buffer優化,添加緩沖區緩解背壓flow.buffer().collect { ... }

6. 錯誤處理

6.1 異常捕獲

try-catch:在收集時捕獲異常。

//收集時捕獲異常try {flow.collect()} catch (e: Exception) {// 處理異常}

catch:在流中處理異常。

//流中出現異常時發射默認值flow.catch { e ->emit(-1) // 發生異常時發射默認值}.collect()

6.2 資源清理

onCompletion:流完成或取消時執行清理。

//流結束時釋放資源flow.onCompletion { cause ->if (cause != null) {// 異常處理}cleanup() // 釋放資源}.collect()

7. 冷熱流轉換

7.1 StateFlow

特點:持有當前狀態,新訂閱者可獲取最新值。

使用示例

//創建StateFlow管理UI狀態val uiState = MutableStateFlow<UIState>(Loading)//更新狀態uiState.value = Success(data)

7.2 SharedFlow

特點:支持多訂閱者,可配置緩存和重放。

使用示例

//創建SharedFlow發射事件val eventFlow = MutableSharedFlow<Event>()//發射事件eventFlow.emit(Event.Click)

7.3 stateInshareIn

stateIn:將冷流轉為 StateFlow

//冷流轉為StateFlow,初始值為0val stateFlow = flow.stateIn(scope = viewModelScope,started = SharingStarted.WhileSubscribed(),initialValue = 0)

shareIn:將冷流轉為 SharedFlow

//冷流轉為SharedFlow,重放1個數據val sharedFlow = flow.shareIn(scope = viewModelScope,started = SharingStarted.Eagerly,replay = 1)

8. 高級主題

8.1 協程上下文切換

flowOn:切換流的執行上下文。

//切換到IO線程執行耗時操作flow.flowOn(Dispatchers.IO)

8.2 取消與資源管理

取消流:通過協程取消。

//啟動收集協程val job = launch {flow.collect()}//取消協程job.cancel()

8.3 與 Room 集成

示例:將 Room 查詢結果轉為流。

//Room Dao接口@Daointerface UserDao {@Query("SELECT * FROM users")fun getUsers(): Flow<List<User>> // 返回Flow}

9. 性能優化與最佳實踐

9.1 避免阻塞操作

正確做法:使用 withContext 切換線程。

//在map操作中切換到IO線程flow.map {withContext(Dispatchers.IO) {// 耗時操作}}

9.2 合理使用背壓策略

場景選擇

buffer:適合生產者與消費者速度波動較大的場景。

conflate:適合只關心最新值的場景(如實時數據)。

9.3 測試與調試

工具推薦

Turbine:用于測試 Flow 的輸出和錯誤。

testCoroutineDispatcher:控制協程執行。

10. Flow 與 RxJava 對比

特性FlowRxJava
協程集成原生支持需通過 RxKotlin 集成
背壓自動處理需顯式處理
線程管理flowOn 簡潔subscribeOn/observeOn
內存管理輕量級,無額外開銷可能存在內存泄漏風險

11. 實戰案例

11.1 網絡請求與數據緩存

//定義網絡請求Flowfun fetchData(): Flow<List<Data>> = flow {val data = api.getData() // 網絡請求emit(data)}.flowOn(Dispatchers.IO)//結合Room緩存val cachedDataFlow = fetchData().catch { e ->emit(roomDao.getData()) // 異常時讀取緩存}.onEach { data ->roomDao.saveData(data) // 保存緩存}

11.2 實時數據更新

//ViewModel管理UI狀態class MyViewModel : ViewModel() {private val _uiState = MutableStateFlow<UIState>(Loading)val uiState: StateFlow<UIState> = _uiStateinit {viewModelScope.launch {_uiState.value = Success(fetchData()) // 更新狀態}}}

12. 總結

Kotlin Flow 憑借其簡潔的 API、與協程的深度集成以及強大的背壓處理能力,成為現代異步編程的首選工具。本文從基礎概念到高級特性全面解析了 Flow,并通過實戰案例展示了其在 Android 開發中的應用。合理使用 Flow 可以顯著提升代碼的可讀性和可維護性,尤其在處理復雜數據流場景時更具優勢。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/79053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/79053.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/79053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

精益數據分析(34/126):深挖電商運營關鍵要點與指標

精益數據分析&#xff08;34/126&#xff09;&#xff1a;深挖電商運營關鍵要點與指標 在創業和數據分析的學習之旅中&#xff0c;我們都在不斷探尋如何讓業務更上一層樓。今天&#xff0c;我依舊帶著和大家共同進步的想法&#xff0c;深入解讀《精益數據分析》中電商運營的關…

Learning vtkjs之ImageCropFilter

過濾器 圖片數據體積裁剪 介紹 vtkImageCropFilter可以裁剪vtkImageData。這只適用于IJK對齊的平面。 請注意&#xff0c;由于CPU限制的裁剪&#xff0c;這在大型數據集上會很慢。 效果 核心代碼 需要實現這個代碼主要邏輯 1、設定的crop的包圍盒 其實主要是IMax IMin JM…

深入理解 C++11 delete 關鍵字:禁用函數的藝術

一、什么是 delete 關鍵字 C11 引入的 delete 關鍵字是一種??顯式禁用函數??的語法機制。它允許開發者主動阻止特定函數的使用&#xff0c;比傳統的私有化聲明更直觀、更安全&#xff0c;且能在編譯期捕獲更多潛在錯誤。 二、為什么需要 delete&#xff1f; 1. 傳統方式…

深度剖析!GPT-image-1 API 開放對 AI 繪畫技術生態的沖擊!

4月24日凌晨&#xff0c;OpenAI正式發布了全新的圖像生成模型“gpt-image-1”&#xff0c;并通過API向全球開發者開放使用&#xff0c;這意味著其GPT-4o的圖像生成能力正式向開發者開放&#xff01; 在這之前&#xff0c;GPT-4o的圖像生成功能于今年3月25日由 OpenAI 創始人兼 …

扣子流程圖批量導入飛書多維表格

文章目錄 整體結構分步驟進行處理1. 程序代碼處理2. 多維表格配置 整體結構 整個代碼塊結構如下&#xff1a; 首先&#xff0c;我們從其他流程中拿到一個數據列表&#xff0c;通過一個循環體&#xff0c;將每一個部分的內容都通過python代碼整理后&#xff0c;使用【插件】的…

【安全掃描器原理】端口掃描

【安全掃描器原理】端口掃描 1.端口掃描基本原理2.TCP掃描3.UDP掃描4.手工掃描1.端口掃描基本原理 以TCP端口為例,其原理是當一個主機向遠端一個服務器的某一個端口提出建立連接的請求,如果對方有此項服務,就會同意建立連接,如果對方未安裝此項服務時,則不會同意建立連接…

FastGPT部署的一些問題整理

在B站學習 圖靈程序員-諸葛 的LangChain快速入門課程之《部署FastGPT構建本地應用》。在我學習課程跟著老師實踐的過程中&#xff0c;踩了一些坑。這篇文章以問答的形式記錄一下學習中的一些問題&#xff0c;主要面向的讀者是&#xff0c;在學習同樣的課程的和部署FastGPT遇到各…

如何查看k8s獲取系統是否清理過docker鏡像

k8s集群某個節點down掉后&#xff0c;pod就會漂移到其他節點&#xff0c;但是在該節點卻又執行了拉取鏡像操作&#xff0c;明明該節點之前部署過該容器的&#xff0c;不知為什么又拉取了一次鏡像&#xff08;鏡像拉取配置的優先使用本地&#xff09;&#xff0c;所以懷疑是觸發…

聚焦智能體未來,領馭科技在微軟創想未來峰會大放異彩

2025年4月23日&#xff0c;微軟創想未來峰會在北京中關村國際創新中心盛大舉行。作為微軟中國南區核心合作伙伴及HKCSP 1T首批授權云服務商&#xff0c;深圳領馭科技有限公司受邀參會&#xff0c;攜瀚鵬工業AI應用解決方案亮相峰會&#xff0c;與全球AI領袖及行業精英共話智能體…

元宇宙2.0:當區塊鏈成為數字世界的憲法

引言&#xff1a;當虛擬世界成為“新大陸” 清晨&#xff0c;你戴上VR設備進入一個由數字建筑構成的城市&#xff0c;這里的地皮屬于全球玩家&#xff0c;街邊的藝術品標著NFT認證碼&#xff0c;咖啡館里的人們用加密貨幣支付咖啡&#xff0c;而社區規則由持有代幣的居民投票決…

力扣hot100——239.滑動窗口最大值

題目鏈接&#xff1a; 239. 滑動窗口最大值 - 力扣&#xff08;LeetCode&#xff09; 優先級隊列 優先級隊列自動按照大小排序&#xff0c;隊首即為最大元素&#xff0c;但取隊首時要注意元素是否在滑動窗口內&#xff0c;如果不在則彈出。 class Solution { public:vector&…

Alibaba國際站商品詳情AP接口概述,json數據示例返回參考

前言 Alibaba國際站商品詳情API&#xff08;通常稱為item_get接口&#xff09;是阿里巴巴開放平臺提供的一項核心服務&#xff0c;允許開發者通過商品ID獲取商品的詳細信息。該接口廣泛應用于電商系統集成、數據分析、競品監控等場景&#xff0c;支持企業自動化獲取商品標題、…

[論文閱讀]Adversarial Semantic Collisions

Adversarial Semantic Collisions Adversarial Semantic Collisions - ACL Anthology Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing (EMNLP) 對抗樣本是相似的輸入但是產生不同的模型輸出&#xff0c;而語義沖突是對抗樣本的逆…

25【干貨】在Arcgis中根據字段屬性重新排序并自動編號的方法(二)

上一篇關于屬性表自動編號的文章因為涉及到代碼&#xff08;【干貨】在Arcgis中根據字段屬性重新排序并自動編號的方法&#xff08;一&#xff09;&#xff09;&#xff0c;擔心大家有些東西確實不熟悉&#xff0c;今天就更新一篇不需要代碼也能達到這個目的的方法。主要的思路…

從后端研發角度出發,使用k8s部署業務系統

k8s&#xff0c;作為目前最流行的容器編排中間件&#xff0c;大家應該都聽說過&#xff0c;很多公司也都在用&#xff0c;但基本都是運維在管理k8s&#xff0c;開發人員一般涉及不到&#xff0c;開發人員只需要寫業務代碼&#xff0c;然后運維人員負責制作鏡像&#xff0c;然后…

Vue3 Echarts 3D圓柱體柱狀圖實現教程以及封裝一個可復用的組件

文章目錄 前言一、實現原理二、series ——type: "pictorialBar" 簡介2.1 常用屬性 三、代碼實戰3.1 封裝一個echarts通用組件 echarts.vue3.2 首先實現一個基礎柱狀圖3.3 添加上下2個橢圓面3.4 進階封裝一個可復用的3D圓形柱狀圖組件 總結 前言 在前端開發的數據可視…

WPF 上位機開發模板

WPF 上位機開發模板 WPF上位機開發模板,集成了基礎操作菜單、海康視覺實時圖像界面、串口通訊、網口通訊、主流PLC通訊、數據存儲、圖片存儲、參數配置、權限管理、第三方webapi接口接入、數據追溯與查詢等功能。 一、項目結構 WpfSupervisor/ ├── Models/ …

瀏覽器插件,提示:此擴展程序未遵循 Chrome 擴展程序的最佳實踐,因此已無法再使用

1、發現的問題如下&#xff1a; 如果你是比較新的 Chrome 135.0.7049.42&#xff08;含&#xff09;以上版本的話&#xff0c;可以通過修改 chorme://flags 來徹底解決。 2、在瀏覽器分別輸入兩個地址&#xff1a; chrome://flags/#extension-manifest-v2-deprecation-disable…

【原創】從s3桶將對象導入ES建立索引,以便快速查找文件

總體功能&#xff1a; 這段程序的作用是&#xff1a; 從指定的S3桶中讀取所有對象的元數據&#xff08;文件名、大小、最后修改時間、存儲類型、ETag等&#xff09;&#xff0c;并把這些信息寫入到Elasticsearch&#xff08;ES&#xff09;中&#xff0c;建立索引&#xff0c…

git 查看用戶信息

在 Git 中查看用戶信息是一項常見的任務&#xff0c;可以幫助你確認當前倉庫的配置或全局的 Git 配置是否正確設置。你可以通過多種方式來查看這些信息。 查看全局用戶信息 全局用戶信息是應用于所有 Git 倉庫的默認設置。要查看全局用戶信息&#xff0c;可以使用以下命令&am…