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)

相关推荐
androidwork42 分钟前
嵌套滚动交互处理总结
android·java·kotlin
橙子199110163 小时前
Kotlin 中的 Object
android·开发语言·kotlin
纳于大麓1 天前
Kotlin基础语法五
android·开发语言·kotlin
移动开发者1号1 天前
嵌套滚动交互处理总结
android·kotlin
移动开发者1号1 天前
Android工程中FTP加密传输与非加密传输的深度解析
android·java·kotlin
yzpyzp2 天前
Kotlin的MutableList和ArrayList区别
android·kotlin
帅次2 天前
Flutter Container 组件详解
android·flutter·ios·小程序·kotlin·iphone·xcode
帅次2 天前
Flutter setState() 状态管理详细使用指南
android·flutter·ios·小程序·kotlin·android studio·iphone
移动开发者1号2 天前
Compose列表项动画实现指南
android·kotlin