一、協程基礎使用
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.Main | UI線程操作 | textView.text = "更新" |
Dispatchers.IO | 網絡/文件IO | Retrofit API調用 |
Dispatchers.Default | CPU密集型計算 | 復雜算法、數據處理 |
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 Flow | Hot 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有什么區別?
對比回答:
特性 | Channel | Flow |
---|---|---|
數據模式 | 點對點單次消費 | 流式多處理 |
冷熱類型 | 熱數據通道 | 默認為冷流 |
使用場景 | 生產者-消費者 | 數據處理管道 |
背壓處理 | 需手動控制 | 內置操作符 |
問題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狀態管理 | StateFlow | MutableStateFlow(initial) |
全局事件通知 | SharedFlow | MutableSharedFlow(replay=1) |
一次性數據傳遞 | Channel | Channel<T>() |
復雜數據處理 | Flow | flow { emit(data) } |
多源優先響應 | Select | select { chan1.onReceive } |
父子協程通信 | 直接訪問變量 | parentVar = value |