Kotlin 協程使用與通信

一、協程基礎使用

1. 協程的三種創建方式

(1)?launch?- 啟動后臺作業
val job = CoroutineScope(Dispatchers.IO).launch {// 后臺操作delay(1000)println("任務完成 ${Thread.currentThread().name}")// 輸出:任務完成 DefaultDispatcher-worker-1
}
job.join() // 等待完成
(2)?async?- 啟動帶結果作業
val deferred = CoroutineScope(Dispatchers.Default).async {delay(500)"計算結果"
}// 獲取結果(會掛起協程)
val result = deferred.await()
println(result) // 輸出:計算結果
(3)?runBlocking?- 阻塞線程啟動
runBlocking {launch {delay(100)println("內部協程")}println("外部協程")
}
// 輸出:
// 外部協程
// 內部協程

2. 調度器選擇(四種核心類型)

調度器用途示例
Dispatchers.MainUI線程操作textView.text = "更新"
Dispatchers.IO網絡/文件IORetrofit API調用
Dispatchers.DefaultCPU密集型計算復雜算法、數據處理
Dispatchers.Unconfined特殊場景不限制線程,慎用
CoroutineScope(Dispatchers.Main).launch {val data = withContext(Dispatchers.IO) { // 切換到IO線程fetchFromNetwork() // 網絡請求}updateUI(data) // 回到主線程更新UI
}

3. 結構化并發(生命周期管理)

class MyActivity : AppCompatActivity() {// 綁定Activity生命周期private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)override fun onCreate() {scope.launch {loadData()}}override fun onDestroy() {scope.cancel() // 取消所有協程}suspend fun loadData() {// ...}
}

二、協程間通信

1. Channel - 點對點通信

(1) 基礎使用
val channel = Channel<Int>()// 生產者
launch {repeat(5) {channel.send(it)delay(100)}channel.close()
}// 消費者
launch {for (value in channel) {println("收到: $value")}
}
// 輸出: 收到: 0, 1, 2, 3, 4
(2) Channel類型對比
類型特性適用場景
RENDEZVOUS無緩沖(默認)嚴格同步
BUFFERED固定大小緩沖允許生產者領先
CONFLATED保留最新值狀態更新
UNLIMITED無限緩沖大批量數據
// 創建不同類型Channel
val rendezvous = Channel<Int>() // 無緩沖
val buffered = Channel<Int>(10) // 緩沖區大小10
val conflated = Channel<Int>(Channel.CONFLATED) // 只保留最新

2. Flow - 異步數據流

(1) 冷流 vs 熱流
特性Cold FlowHot Flow (SharedFlow)
啟動收集時啟動獨立于收集者
數據每次收集重新發射共享數據流
示例數據庫查詢實時位置更新
(2) Flow基本使用
fun dataFlow(): Flow<Int> = flow {repeat(5) {delay(100)emit(it) // 發射數據}
}// 收集數據
CoroutineScope(Dispatchers.Main).launch {dataFlow().filter { it % 2 == 0 } // 過濾偶數.map { it * 2 } // 轉換.collect { value -> // 收集println("值: $value")}
}
// 輸出: 值: 0, 值: 4, 值: 8

3. SharedFlow & StateFlow - 狀態管理

(1) SharedFlow - 事件廣播
// 創建共享流(帶重播1個事件)
val sharedFlow = MutableSharedFlow<Event>(replay = 1)// 發送事件
launch {sharedFlow.emit(Event.UPDATE)
}// 多個接收者
repeat(3) { i ->launch {sharedFlow.collect { event ->println("接收者$i: $event")}}
}
(2) StateFlow - 狀態容器
// 創建狀態容器(初始值0)
val stateFlow = MutableStateFlow(0)// 更新狀態
launch {repeat(10) {delay(200)stateFlow.value = it}
}// 監聽狀態變化
launch {stateFlow.collect { state ->println("當前狀態: $state")}
}
// 輸出: 當前狀態: 0,1,2,...,9

4. Select - 多路復用

val chan1 = Channel<String>()
val chan2 = Channel<String>()launch { delay(50); chan1.send("A") }
launch { delay(30); chan2.send("B") }// 選擇最先到達的消息
val result = select<String> {chan1.onReceive { it }chan2.onReceive { it }
}println("結果: $result") // 輸出: 結果: B

三、常見問題與答案

問題1:launch和async有什么區別?

標準回答:

  • launch?啟動不需要返回結果的作業,返回Job對象用于控制生命周期

  • async?啟動需要返回結果的作業,返回Deferred對象,通過await()獲取結果

  • async?通常用于并行任務,launch用于后臺執行

問題2:Channel和Flow有什么區別?

對比回答:

特性ChannelFlow
數據模式點對點單次消費流式多處理
冷熱類型熱數據通道默認為冷流
使用場景生產者-消費者數據處理管道
背壓處理需手動控制內置操作符

問題3:StateFlow和LiveData如何選擇?

  • 選擇StateFlow

    • 純Kotlin項目

    • 需要復雜數據轉換

    • 需要協程集成

  • 選擇LiveData

    • 現有Java代碼庫

    • 簡單UI狀態管理

    • 需要生命周期感知

問題4:如何在協程中處理異常?

最佳實踐:

// 方式1:try-catch
launch {try {riskyOperation()} catch (e: Exception) {handleError(e)}
}// 方式2:CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { _, e ->println("捕獲異常: $e")
}CoroutineScope(Dispatchers.IO + handler).launch {throw RuntimeException("測試異常")
}

四、協程通信模式選擇指南

場景推薦方案代碼示例
UI狀態管理StateFlowMutableStateFlow(initial)
全局事件通知SharedFlowMutableSharedFlow(replay=1)
一次性數據傳遞ChannelChannel<T>()
復雜數據處理Flowflow { emit(data) }
多源優先響應Selectselect { chan1.onReceive }
父子協程通信直接訪問變量parentVar = value

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

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

相關文章

Ubuntu服務器(公網)- Ubuntu客戶端(內網)的FRP內網穿透配置教程

以下是為Ubuntu服務器&#xff08;公網&#xff09;- Ubuntu客戶端&#xff08;內網&#xff09;的FRP內網穿透配置教程&#xff0c;基于最新版本&#xff08;2025年6月&#xff0c;使用frp_0.61.1_linux_amd64&#xff09;整理&#xff1a; 一、服務端配置&#xff08;公網Ubu…

什么是哈希函數(SHA-256)

SHA-256 是區塊鏈系統中最核心的加密基礎之一&#xff0c;尤其是在比特幣、以太坊、文件存證等場景中扮演“指紋識別器”的角色。下面是對它的詳細講解&#xff0c;包括原理、特點、用途和代碼示例。 &#x1f4cc; 一、什么是 SHA-256&#xff1f; SHA-256 是一種密碼學哈希函…

大模型的“Tomcat”:一文讀懂AI推理引擎(Inference Engine)

點擊下方“JavaEdge”&#xff0c;選擇“設為星標” 第一時間關注技術干貨&#xff01; 免責聲明~ 任何文章不要過度深思&#xff01; 萬事萬物都經不起審視&#xff0c;因為世上沒有同樣的成長環境&#xff0c;也沒有同樣的認知水平&#xff0c;更「沒有適用于所有人的解決方案…

《從0到1:C/C++音視頻開發自學完全指南》

從0到1&#xff1a;C/C音視頻開發自學完全指南 一、開篇&#xff1a;為什么選擇C/C切入音視頻開發&#xff1f; 當你刷著抖音短視頻、參加騰訊會議、觀看B站直播時&#xff0c;背后都是音視頻技術在支撐。根據艾瑞咨詢數據&#xff0c;2024年中國音視頻相關產業規模已突破5000…

微信小程序之單行溢出隱藏和雙行溢出隱藏

首先&#xff0c;我們做個text&#xff0c;加入了一個長文本&#xff0c;就像下面那樣&#xff1a; wxml : <view class"container"><text>劉德華&#xff08;Andy Lau&#xff09;&#xff0c;1961年9月27日出生于中國香港&#xff0c;華語影視男演員、…

PHP安裝使用教程

一、PHP 簡介 PHP&#xff08;Hypertext Preprocessor&#xff09;是一種廣泛應用的開源服務器端腳本語言&#xff0c;尤其適用于 Web 開發&#xff0c;可嵌入 HTML 中使用。其運行速度快、易學易用&#xff0c;支持多種數據庫和平臺。 二、PHP 安裝教程 2.1 支持平臺 PHP 支…

ThreadLocal、InheritableThreadLocal與TransmittableThreadLocal深度解析

文章目錄 一、概念說明1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 二、使用場景1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 三、存在的問題1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 四、示例…

ERP系統Bug記錄

2025.06.30 2025/06/30-10:51:02 [http-nio-9999-exec-3] com.yxx.jsh.erp.service.LogService - 異常碼[300],異常提示[數據查詢異常],異常[{}] java.lang.NullPointerException: nullat com.yxx.jsh.erp.base.TableSupport.getBuildPageRequest(TableSupport.java:46)at com…

C# Avalonia 的 Source Generators 用處

C# Avalonia 的 Source Generators 用處 文章目錄 **1. 自動生成 MVVM 綁定代碼****2. 強類型 XAML 數據綁定****3. 自動注冊視圖&#xff08;View&#xff09;與視圖模型&#xff08;ViewModel&#xff09;****4. 資源文件與本地化的強類型訪問****5. 路由事件與命令的自動化處…

stm32之測量占空比

#include "tim4.h"void TIM4_Init(void) {// 開啟時鐘RCC->APB1ENR | RCC_APB1ENR_TIM4EN;RCC->APB2ENR | RCC_APB2ENR_IOPBEN; // 使用 TIM4 的 GPIOB 時鐘// 配置 PB6 為浮空輸入 CNF 01 MODE 00GPIOB->CRL & ~GPIO_CRL_MODE6;GPIOB->CRL & ~G…

工廠模式 - Flutter中的UI組件工廠,按需生產各種“產品

想要動態創建不同風格的按鈕&#xff1f;想一鍵切換整個主題&#xff1f;工廠模式就是你的"生產流水線"&#xff01; 想象一下這個場景&#xff1a; 你決定擴大奶茶店業務&#xff0c;推出兩個品牌系列&#xff1a; 經典系列&#xff1a;傳統珍珠奶茶&#xff0c;紅…

基于 SpringBoot+Vue.js+ElementUI 的 Cosplay 論壇設計與實現7000字論文

基于 SpringBootVue.jsElementUI 的 Cosplay 論壇設計與實現 摘要 本論文設計并實現了一個基于 SpringBoot、Vue.js 和 ElementUI 的 Cosplay 論壇平臺。該平臺旨在為 Cosplay 愛好者提供一個集作品展示、交流互動、活動組織于一體的綜合性社區。論文首先分析了 Cosplay 論壇…

超標量處理器11-Alpha21264 處理器

1. 簡介 21264處理器是一款4-way&#xff0c;亂序執行的超標量處理器&#xff0c;采用0.35um的CMOS工藝&#xff0c;工作電壓是2.2V, 工作頻率是466-667MHz; 處理器能支持60條指令&#xff0c;也即ROB的深度是60; Load/Store指令也采取亂序執行, 總共7級流水。I-CACHE和D-CACH…

Spring 中 Bean 的生命周期

一、什么是 Bean 生命周期&#xff1f; Spring 中的 Bean 生命周期是指一個 Bean 從 被容器創建到 最終銷毀 所經歷的一系列過程。 它體現了 Spring IOC 容器在管理 Bean 實例時所執行的各個鉤子流程&#xff0c;包括初始化、依賴注入、增強處理、銷毀等多個環節。 二、Bean 生…

C++ 中 std::string 與 QString 的深度剖析

在 C 編程領域&#xff0c;std::string 和 QString 是兩種廣泛應用的字符串類型&#xff0c;它們在設計理念、功能特性以及適用場景上都呈現出鮮明的特點。本文將從多個維度對這兩種字符串類型進行深度剖析&#xff0c;并詳細闡述它們之間的相互轉化方法。 std::string 是 C 標…

不止于“修補”:我如何用Adobe AI重塑設計與視頻敘事流程

最近我深度體驗了一把來自英國Parvis School of Economics and Music的Adobe正版教育訂閱&#xff0c;在把玩PhotoShop、Premiere Pro這些“老伙計”的新功能時&#xff0c;的確挖到了一些寶藏&#xff0c;覺得非常有必要與大家說道說道。首先得聊聊這個訂閱給我的直觀感受&…

重頭開始學ROS(5)---阿克曼底盤的URDF建模與Gazebo控制(使用Xacro優化)

阿克曼底盤的URDF建模與Gazebo控制&#xff08;使用Xacro優化&#xff09; 阿克曼底盤建模 建模 我們使用后輪驅動&#xff0c;前輪轉向的阿克曼底盤模型。 那么對于后輪只需進行正常的continous joint連接即可 對于前輪&#xff0c;有兩個自由度&#xff0c;旋轉和轉向&…

RabbitMq中啟用NIO

? 所屬類 com.rabbitmq.client.ConnectionFactory&#x1f9e0; 使用背景 RabbitMQ Java 客戶端默認使用傳統的 阻塞 I/O (java.net.Socket) 實現。如果你希望&#xff1a; 更好地控制 線程數獲得更好的 并發性能降低 每個連接的線程占用在高并發連接或消費者數量較多的系統…

[Dify]-基礎篇2- 如何注冊并快速上手 Dify 平臺

在生成式 AI 應用開發新時代,如何快速搭建一個高效、可維護、易上線的 AI 工具,是每位開發者關注的核心。Dify,正是為此而生的一站式平臺。本篇將以新手視角,帶你從注冊賬號、配置環境,到構建應用、部署上線,手把手完成你的第一個 AI 項目。 注冊并設置工作環境 1. 賬號…

Java面試寶典:基礎七

153. 如何實現對象克隆? 答: 對象克隆有兩種主要方式: 淺克隆:實現Cloneable接口并重寫Object.clone() class Person implements Cloneable {String name;Car car; // 引用類型@Override