在 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)