Kotlin中协程的关键函数分析

在 Kotlin 中,协程的关键函数主要来自 kotlinx.coroutines 库。

1,协程作用域(Scopes)

CoroutineScope(context: CoroutineContext):定义协程的作用域,用于管理协程的启动和取消。创建独立的协程作用域,所有子协程完成前不会结束。

scss 复制代码
import kotlinx.coroutines.CoroutineScope

val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
coroutineScope.launch {...}
coroutineScope.async {...}
coroutineScope.cancel() // 取消所有子协程

在compose中,

ini 复制代码
import androidx.compose.runtime.rememberCoroutineScope

val coroutineScope = rememberCoroutineScope()
coroutineScope.launch {...}
coroutineScope.async {...}

supervisorScope:子协程失败不会全部取消,即子协程异常不影响其他子协程。

scss 复制代码
import kotlinx.coroutines.supervisorScope
supervisorScope {
    launch { task1() } // 失败不会取消其他子协程
    launch { task2() }
}

2,协程构建器(Coroutine Builders)

用于启动新协程的核心函数:launch, async, runBlocking.

launch(context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit): Job

启动一个不阻塞当前线程的新协程(通常用于执行后台任务,不返回结果),返回一个 Job 对象用于管理协程生命周期(如取消)。

scss 复制代码
val job = CoroutineScope(Dispatchers.Main).launch {
    delay(1000)
    println("Done")
}
job.join() // 等待协程完成

async 启动一个可返回结果的协程(通过 Deferred 对象获取结果)。

async(context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T): Deferred

启动一个返回 Deferred 结果的协程,可通过 .await() 获取结果。

dart 复制代码
val deferred = scope.async { 
    // 执行计算
}
val result = deferred.await() // 获取结果(会挂起协程)

runBlocking,其用途是在非协程环境中启动协程,会阻塞当前线程直到协程完成。 主要场景用于测试或启动主协程。

runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T

阻塞当前线程直到协程完成,常用于测试或主函数入口。即runBlocking 在阻塞当前线程的上下文中启动协程(主要用于测试或 main 函数)。

3,上下文切换与调度 核心函数是withContext和Dispatchers

withContext(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T withContext 临时切换协程的上下文(如线程池),执行完成后返回结果。

withContext其用途是在指定的调度器中执行代码块,并返回结果。其特点是会挂起当前协程,但不会阻塞线程。

kotlin 复制代码
scope.launch {
    val result = withContext(Dispatchers.IO) { 
        // 在 IO 线程执行阻塞操作
        fetchData() 
    }
    // 自动切回原上下文
}

import kotlinx.coroutines.*

suspend fun fetchData(): String = withContext(Dispatchers.IO) {
    // 模拟IO操作
    delay(1000)
    "Data from IO thread"
}

调度器(Dispatchers):

Dispatchers.Default:CPU 密集型任务(线程池)

Dispatchers.IO:I/O 阻塞操作(优化后的线程池)

Dispatchers.Main:Android 主线程(需依赖 kotlinx-coroutines-android)

Dispatchers.Unconfined:不限制执行线程(谨慎使用)

4,挂起函数(Suspending Functions)

在Kotlin协程中,每一个挂起函数都会被编译成一个状态机,其中每个挂起点都会分割成多个部分。每个部分都是一个 Continuation ,当挂起函数需要恢复执行时,就会调用Continuation 的 resume 方法。

kotlin 复制代码
interface Continuation<in T> {
	val context: CoroutineContext
	fun resume(value: T) // resume用于成功恢复协程的执行,并传递一个结果值。
	fun resumeWithException(exception: Throwable) // 以异常恢复挂起的协程,用于恢复协程的执行,但传递一个异常,导致协程在挂起点抛出该异常。
}

resume和resumeWithException 方法通常与 suspendCoroutine 构建器配合使用,suspendCoroutine用于手动控制协程恢复的底层构建器。

kotlin 复制代码
suspend fun fetchData(): String = suspendCoroutine { cont ->
    // 模拟异步回调
    thread {
        Thread.sleep(1000)
        if (success) {
            cont.resume("Data received") // 成功恢复
        } else {
            cont.resumeWithException(IOException()) // 失败恢复
        }
    }
}

一般推荐使用 suspendCancellableCoroutine。

kotlin 复制代码
suspend fun downloadFile(): ByteArray = suspendCancellableCoroutine { cont ->
    val call = apiService.downloadFile().enqueue(
        object : Callback {
            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    cont.resume(response.body())
                } else {
                    cont.resumeWithException(HttpException(response))
                }
            }
            override fun onFailure(call: Call, t: Throwable) {
                cont.resumeWithException(t)
            }
        })
    
    // 提供取消支持
    cont.invokeOnCancellation { call.cancel() }
}

协程中可暂停执行的函数,使用 suspend 关键字修饰。

delay(timeMillis: Long):非阻塞式挂起协程指定时间,释放线程供其他任务使用。

yield():主动挂起协程,让出当前协程执行权,允许同一线程的其他协程运行(常用于公平调度)。

5, 取消与异常处理

cancel(cause: CancellationException? = null):取消协程或作用域内的所有协程,释放资源。即cancel()取消协程(通过 Job 对象)。

scss 复制代码
val job = scope.launch { ... }
job.cancel() // 取消协程
scope.cancel() // 取消作用域内所有协程

suspendCancellableCoroutine

用途:将回调式 API 转换为协程式 API。

kotlin 复制代码
suspend fun getUserData(userId: String): User = suspendCancellableCoroutine { continuation ->
    // 假设这是一个回调式 API
    userRepository.getUser(userId) { user, error ->
        if (error != null) {
            continuation.resumeWithException(error)
        } else {
            continuation.resume(user)
        }
    }
}

isActive:检查协程是否仍处于活动状态。

while (isActive) { ... } // 在取消时自动退出循环

ensureActive():如果协程已取消,立即抛出 CancellationException。 ensureActive() // 手动检查取消状态

withTimeout():设置协程执行超时 withTimeout(3000) { // 超时抛出 TimeoutCancellationException longRunningTask() }

CoroutineExceptionHandler:全局异常处理器(非函数,但需配合协程使用)

scss 复制代码
val handler = CoroutineExceptionHandler { _, exception ->
    println("Caught $exception")
}
CoroutineScope(Dispatchers.Main + handler).launch {
    throw RuntimeException("Error") // 异常会被 handler 捕获
}

6,流处理(Flow API)

flow { ... }:创建冷流(Cold Stream)。

scss 复制代码
fun getDataFlow() = flow {
    emit(1)
    emit(2)
}

collect():收集流的值。

scss 复制代码
scope.launch {
    getDataFlow().collect { 
		value -> println(value)
    }
}

6,关键概念总结

函数/概念 作用

launch: 启动不返回结果的协程

async + await: 启动可返回结果的协程

runBlocking: 阻塞线程直到协程完成(用于测试)

withContext: 切换协程上下文(如线程池)

coroutineScope: 创建结构化并发作用域(子协程失败会传播取消) supervisorScope:子协程失败不会传播取消

delay: 非阻塞挂起

cancel + isActive: 协程取消控制

Flow: 异步流处理(类似 RxJava)

相关推荐
恋猫de小郭7 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
androidwork9 小时前
深入解析内存抖动:定位与修复实战(Kotlin版)
android·kotlin
移动开发者1号15 小时前
ReLinker优化So库加载指南
android·kotlin
移动开发者1号15 小时前
剖析 Systrace:定位 UI 线程阻塞的终极指南
android·kotlin
移动开发者1号15 小时前
深入解析内存抖动:定位与修复实战(Kotlin版)
android·kotlin
Try02118 小时前
Kotlin中Lambda表达式妙用:超越基础语法的力量
kotlin
泓博21 小时前
KMP(Kotlin Multiplatform)改造(Android/iOS)老项目
android·ios·kotlin
移动开发者1号21 小时前
使用Baseline Profile提升Android应用启动速度的终极指南
android·kotlin
移动开发者1号21 小时前
解析 Android Doze 模式与唤醒对齐
android·kotlin
Devil枫1 天前
Kotlin扩展函数与属性
开发语言·python·kotlin