Kotlin Flow 操作符

前言

Kotlin 擁有函數式編程的能力,使用Kotlin開發,可以簡化開發代碼,層次清晰,利于閱讀。

然而Kotlin擁有操作符很多,其中就包括了flow。Kotlin Flow 如此受歡迎大部分歸功于其豐富、簡潔的操作符,巧妙使用Flow操作符可以大大簡化我們的程序結構,提升可讀性與可維護性。本篇文章列舉一些比較常用 Kotlin 操作符,通過關鍵原理與使用場景列子來講解Flow操作符。

1. collect接收操作符

用于數據接收,此操作符沒有返回對象,后面不可再添加操作符:


fun flowCollect() {
//流啟動viewModelScope.launch {flow {for (i in 1..3) {Log.d("TAG"," flowCollect $i")emit(i)delay(1000)}}.collect {Log.d("TAG"," collect $it")}//后面不可再接收其他操作符}}

2. launchIn操作符

流的啟動主要有兩種,一種是上面的作用域.launch啟動一個流,用collect操作符接收數據;

一種是launchIn操作符啟動流,官方不建議用這種,可能出于數據安全考慮,一般建議在onResume方法調用后啟動協程,因為怕數據接收了,但View還沒創建出來。但鏈式調用真的很好用,用onEach操作符接收數據。

flow {for (i in 1..3) {Log.d("TAG"," flowCollect $i")emit(i)delay(1000)}}.onCompletion {Log.d("TAG","onCompletion ")}.launchIn(viewModelScope)//在ViewModel中,直接launchIn在ViewModelScope作用域

3. onEach操作符

返回一個流,該流在上游流的每個值向下游發出之前調用給定的操作。也可以用來接收數據,與上面collect不同的是此操作符返回流,我們后面還可接其他操作符。上面的launchIn操作符啟動時,可用于接收數據。

 fun flowOnEach() {flow {for (i in 1..3) {LogUtils.d("Emitting $i")emit(i)delay(1000)}}.onEach {LogUtils.d("onEach $it")}.onCompletion {LogUtils.d("onCompletion ")}.launchIn(viewModelScope)}

4. reduce操作符

reduce 操作符可以將所有數據累加(加減乘除)得到一個結果,如下所示:
在這里插入圖片描述

    fun testReduce(){val result = listOf(1, 2, 3).reduce { a, b ->a + b}print("list reduce result:$result")}

查看測試結果輸出如下:
在這里插入圖片描述

注意??:
1: 如果 flow 中沒有數據,將拋出異常。如不希望拋異常,可使用 reduceOrNull 方法。
2: reduce 操作符不能變換數據類型。比如,Int 集合的結果不能轉換成 String 結果。

5. fold操作符

fold 和 reduce 很類似,但是 fold 可以變換數據類型
在這里插入圖片描述

有時候,我們不需要一個結果值,而是需要繼續操 flow,可使用 runningFold :

flowOf(1, 2, 3).runningFold("a") { a, b ->a + b
}.collect {println(it)
}

查看輸出結果:

a
a1
a12
a123

同樣的,reduce 也有類似的方法 runningReduce:

flowOf(1, 2, 3).runningReduce { a, b ->a + b
}.collect {println(it)
}

查看輸出結果:

1
3
6

6. debounce操作符

debounce 需要傳遞一個毫秒值參數,功能是:只有達到指定時間后才發出數據,最后一個數據一定會發出。
在這里插入圖片描述

例如,定義 1000 毫秒,也就是 1 秒,被觀察者發出數據,1秒后,觀察者收到數據,如果 1 秒內多次發出數據,則重置計算時間。

flow {emit(1)delay(500)emit(2)delay(550)emit(3)delay(1000)emit(4)delay(1010)
}.debounce(1000
).collect {println(it)
}

查看輸出結果,只有休眠1000和1010符合要求:

3
4

所以,rebounce 的應用場景是限流功能。

7. sample操作符

sample 和 debounce 很像,區別是:在規定時間內,只發送一個數據:
在這里插入圖片描述

flow {repeat(4) {emit(it)delay(50)}
}.sample(100).collect {println(it)
}

輸出結果:

1
3

所以,sample 的應用場景是截流功能。

8. flatmapMerge操作符

簡單的說就是獲得兩個 flow 的乘積或全排列,合并并且平鋪,發出一個 flow。
在這里插入圖片描述

flowOf(1, 3).flatMapMerge {flowOf("$it a", "$it b")
}.collect {println(it)
}

輸出結果:

1 a
1 b
3 a
3 b

注意??:flatmapMerge 還有一個特性,flatmapMerge 可以設置并發量,可以理解為 flatmapMerge 是線程安全的,而 flatmapConcat 不是線程安全的。會在下一個操作符里提及。

9. flatmapConcat操作符

舉個列子:

flowOf(1, 3).flatMapConcat {flowOf("a", "b", "c")
}.collect {println(it)
}

在這里插入圖片描述

功能和 flatmapMerge 一致,不同的是 flatmapMerge 可以設置并發量,可以理解為 flatmapMerge 是線程安全的,而 flatmapConcat 不是線程安全的。

本質上,在 flatmapMerge 的并發參數設置為 1 時,和 flatmapConcat 基本一致,而并發參數大于 1 時,采用 channel 的方式發出數據,具體內容請參閱源碼。

10. buffer操作符

介紹 buffer 的時候,先要看這樣一段代碼:

flowOf("A", "B", "C", "D")
.onEach {println("1 $it")
}
.collect { println("2 $it") }

我們注意查看一下輸出結果:

1 A
2 A
1 B
2 B
1 C
2 C
1 D
2 D

如果我們加上 buffer 的代碼:

flowOf("A", "B", "C", "D")
.onEach {println("1 $it")
}
.buffer()
.collect { println("2 $it") }

在查看一下加上 buffer 的代碼的輸出結果:

1 A
1 B
1 C
1 D
2 A
2 B
2 C
2 D

對比倆次輸出結果,會發現輸出內容有所不同,buffer 操作符可以改變收發順序,像有一個容器作為緩沖似的,在容器滿了或結束時,下游開始接到數據,onEach 添加延遲,效果更明顯。

11 combine操作符

合并兩個 flow,長的一方會持續接受到短的一方的最后一個數據,直到結束:

flowOf(1, 3).combine(flowOf("a", "b", "c")
) { a, b -> b + a }
.collect {println(it)
}

查看輸出結果如下:

a1
b3
c3

12. zip操作符

也是合并兩個 flow,結果長度與短的 flow 一致,很像木桶原理。

    fun testZip() {runBlocking {val time = measureTimeMillis {val flow1 = flow { emit("a") emit ("b") emit ("c") emit ("d") }val flow2 = flow { emit("1") emit ("2") } flow1 . zip (flow2) { sex, subject -> "$sex-->$subject" }.collect { println(it) }} println ("use time:$time")}}

查看輸出結果:

a-->1
b-->2
use time:71

通過輸出可以看出flow2先結束了,并且flow1沒發送完成。
zip原理簡單來說:
在這里插入圖片描述
可以看出,zip的特點:

短的Flow結束,另一個Flow也結束。

13. flatMapLatest操作符

與 collectLatest 操作符類似,處理最新值,也有相對應的“最新”展平模式,在發出新流后立即取消先前流的收集。 這由 flatMapLatest 操作符來實現。

14. distinctUntilChanged操作符

和前一個數據不同,才能收到,和前一個數據相同,則會被過濾掉。
在這里插入圖片描述

flowOf(1, 1, 2, 2, 3, 1).distinctUntilChanged().collect {println(it)
}

運行查看輸出結果:

1
2
3
1

總結

Kotlin 擁有函數式編程的能力,同時Kotlin擁有很多操作符,其中就包括了flow。合理使用Kotlin操作符可以使我們的代碼更加簡化,層次清晰,利于閱讀。因此,要靈活使用Kotlin操作符。

參考:

  1. 協程文檔
  2. 協程中文網
  3. 這一次,讓Kotlin Flow 操作符真正好用起來
  4. Kotlin 協程Flow主要操作符(一)
  5. Kotlin 協程Flow主要操作符(二)

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

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

相關文章

【矩陣論】Chapter 7—Hermite矩陣與正定矩陣知識點總結復習

文章目錄 1 Hermite矩陣2 Hermite二次型3 Hermite正定(非負定矩陣)4 矩陣不等式 1 Hermite矩陣 定義 設 A A A為 n n n階方陣,如果稱 A A A為Hermite矩陣,則需滿足 A H A A^HA AHA,其中 A H A^H AH表示 A A A的共軛轉…

數據結構入門————樹(C語言/零基礎/小白/新手+模擬實現+例題講解)

目錄 1. 樹的概念及其結構 1.1 樹的概念: 1.2 樹的相關概念: 1.3 樹的表示方法: ?編輯 1.4 樹的應用: 2. 二叉樹的概念及其結構 2.1 概念: 2.2 特點: 2.3 特殊二叉樹: 2.4 二叉樹的性質&#xf…

【深度學習】注意力機制(一)

本文介紹一些注意力機制的實現,包括SE/ECA/GE/A2-Net/GC/CBAM。 目錄 一、SE(Squeeze-and-Excitation) 二、ECA(Efficient Channel Attention) 三、GE(Gather-Excite) 四、A2-Net(Double A…

二維碼智慧門牌管理系統升級解決方案:數字鑒權

文章目錄 前言一、數字鑒權的核心機制二、數字鑒權的意義和應用 前言 隨著科技的飛速發展,我們的生活逐漸進入數字化時代。在這個數字化的過程中,數據的安全性和門牌信息的保障變得至關重要。今天,我們要介紹的是二維碼智慧門牌管理系統升級…

【論文復現】zoedepth踩坑

注意模型IO: 保證輸入、輸出精度、類型與復現目標一致。 模型推理的代碼 from torchvision import transforms def image_to_tensor(img_path, unsqueezeTrue):rgb transforms.ToTensor()(Image.open(img_path))if unsqueeze:rgb rgb.unsqueeze(0)return rgbdef…

dockerdesktop 導出鏡像,導入鏡像

總體思路 備份時 容器 > 鏡像 > 本地文件 恢復時 本地文件 > 鏡像 > 容器 備份步驟 首先,把容器生成為鏡像 docker commit [容器名稱] [鏡像名稱] 示例 docker commit nginx mynginx然后,把鏡像備份為本地文件,如果使用的是Docker Desktop,打包備份的文件會自動存…

機器學習筆記 - 基于C# + .net framework 4.8的ONNX Runtime進行分類推理

該示例是從官方抄的,演示了如何使用 Onnx Runtime C# API 運行預訓練的 ResNet50 v2 ONNX 模型。 我這里的環境基于.net framework 4.8的一個winform項目,主要依賴下面版本的相關庫。 Microsoft.Bcl.Numerics.8.0.0 Microsoft.ML.OnnxRuntime.Gpu.1.16.3 SixLabors.ImageShar…

MyString:string類的模擬實現 1

MyString:string類的模擬實現 前言: 為了區分標準庫中的string,避免編譯沖突,使用命名空間 MyString。 namespace MyString {class string{private:char* _str;size_t _size;size_t _capacity;const static size_t npos -1;// C標…

2023年 - 我的程序員之旅和成長故事

2023年 - 我的程序員之旅和成長故事 🔥 1.前言 大家好,我是Leo哥🫣🫣🫣,今天咱們不聊技術,聊聊我自己,聊聊我從2023年年初到現在的一些經歷和故事,我也很愿意我的故事分…

TS學習——快速入門

TypeScript簡介 TypeScript是JavaScript的超集。它對JS進行了擴展,向JS中引入了類型的概念,并添加了許多新的特性。TS代碼需要通過編譯器編譯為JS,然后再交由JS解析器執行。TS完全兼容JS,換言之,任何的JS代碼都可以直…

Android 樣式小結

關于作者:CSDN內容合伙人、技術專家, 從零開始做日活千萬級APP。 專注于分享各領域原創系列文章 ,擅長java后端、移動開發、商業變現、人工智能等,希望大家多多支持。 目錄 一、導讀二、概覽三、使用3.1 創建并應用樣式3.2 創建并…

DJI ONBOARD SDK—— 基礎控制功能 Joystick的講解,使用和擴展

DJI ONBOARD SDK/DJI OSDK ROS—— 基礎控制功能 Joystick的使用 概述 使用OSDK/OSDK_ROS 的無人機飛行控制功能,能夠設置并獲取無人機各項基礎參數,控制無人機執行基礎飛行動作,通過Joystick 功能控制無人機執行復雜的飛行動作。 Joystic…

【精彩回顧】恒拓高科亮相第十一屆深圳軍博會

2023年12月6日-8日,由中國和平利用軍工技術協會、全國工商聯科技裝備業商會、深圳市國防科技工業協會等單位主辦以及政府相關部門支持,深圳企發展覽有限公司承的“2023第11屆中國(深圳)軍民兩用科技裝備博覽會(深圳軍博…

02 CSS基礎入門

文章目錄 一、CSS介紹1. 簡介2. 相關網站3. HTML引入方式 二、選擇器1. 標簽選擇器2. 類選擇器3. ID選擇器4. 群組選擇器 四、樣式1. 字體樣式2. 文本樣式3. 邊框樣式4. 表格樣式 五、模型和布局1. 盒子模型2. 網頁布局 一、CSS介紹 1. 簡介 CSS主要用于控制網頁的外觀&#…

C#如何使用SqlSugar操作MySQL/SQL Server數據庫

一. SqlSugar 連接MySQL數據庫 public class MySqlCNHelper : Singleton<MySqlCNHelper>{public static SqlSugarClient CnDB;public void InitDB() {//--------------------MySQL--------------------CnDB new SqlSugarClient(new ConnectionConfig(){ConnectionString…

窮舉問題-搬磚(for循環)

某工地需要搬運磚塊&#xff0c;已知男人一人搬3塊&#xff0c;女人一人搬2塊&#xff0c;小孩兩人搬1塊。如果想用n人正好搬n塊磚&#xff0c;問有多少種搬法&#xff1f; 輸入格式: 輸入在一行中給出一個正整數n。 輸出格式: 輸出在每一行顯示一種方案&#xff0c;按照&q…

玩轉大數據12:大數據安全與隱私保護策略

1. 引言 大數據的快速發展&#xff0c;為各行各業帶來了巨大的變革&#xff0c;也帶來了新的安全和隱私挑戰。大數據系統通常處理大量敏感數據&#xff0c;包括個人身份信息、財務信息、健康信息等。如果這些數據被泄露或濫用&#xff0c;可能會對個人、企業和社會造成嚴重的損…

Unity 資源管理之Resources

Resources是一個特殊的文件夾&#xff0c;用于存放運行時加載的資源。 Resources文件夾中可以放置各種類型的資源文件&#xff0c;如紋理、模型、音頻、預制體等&#xff0c;一般用來存儲預制體和紋理信息。 通過API可以加載和訪問該文件夾及其子文件夾中的資源。 當我們打包…

大數據Doris(三十五):Unique模型(唯一主鍵)介紹

文章目錄 Unique模型(唯一主鍵)介紹 一、創建doris表 二、插入數據

【華為OD題庫-076】執行時長/GPU算力-Java

題目 為了充分發揮GPU算力&#xff0c;需要盡可能多的將任務交給GPU執行&#xff0c;現在有一個任務數組&#xff0c;數組元素表示在這1秒內新增的任務個數且每秒都有新增任務。 假設GPU最多一次執行n個任務&#xff0c;一次執行耗時1秒&#xff0c;在保證GPU不空閑情況下&…