在 Kotlin 协程(Coroutines) 中,协程是一种轻量级的线程管理工具,旨在简化异步编程和并发任务。它通过 挂起(suspend) 而非阻塞线程的方式实现高效的任务调度,显著提升代码的可读性和性能。以下是其核心概念和实际应用的深度解析:
- 协程的本质与优势
轻量级线程
协程的调度由 Kotlin 运行时管理,而非操作系统。一个线程可运行多个协程,避免了传统线程的创建和切换开销。
示例:启动 10 万个协程仅需少量内存,而同样数量的线程会崩溃。
结构化并发(Structured Concurrency)
通过 CoroutineScope 管理协程生命周期,避免资源泄漏。子协程会随父协程取消而自动取消。
挂起函数(Suspend Functions)
使用 suspend 关键字标记的函数可在不阻塞线程的情况下暂停和恢复,底层通过 状态机 实现。
2. 核心组件与用法
关键类与作用
组件 | 用途 |
---|---|
CoroutineScope |
定义协程作用域(如 ViewModel 的 viewModelScope )。 |
Dispatcher |
指定协程运行的线程(如 Dispatchers.IO 、Dispatchers.Main )。 |
Job |
控制协程生命周期(取消、等待完成)。 |
Deferred |
带返回值的异步任务(通过 async 启动)。 |
基础示例
// 启动一个协程
viewModelScope.launch(Dispatchers.IO) {
val data = fetchData() // 挂起函数
withContext(Dispatchers.Main) {
updateUI(data) // 切回主线程更新UI
}
}
// 并发任务
val result1 = async { fetchFromApi1() }
val result2 = async { fetchFromApi2() }
val combined = result1.await() + result2.await()
协程与线程的对比
特性 协程 线程
创建开销 极低(KB 级内存) 高(MB 级内存)
切换成本 无系统调用,仅状态切换 需内核介入,开销大
阻塞行为 挂起(不阻塞线程) 阻塞线程
并发管理 结构化并发,自动取消 需手动管理(如 Executor)实际应用场景
网络请求
结合 Retrofit 使用挂起函数,避免回调地狱:
@GET("users")
suspend fun getUsers(): List<User> // Retrofit 挂起接口
viewModelScope.launch {
try {
val users = api.getUsers() // 同步写法,异步执行
} catch (e: Exception) { /* 异常处理 */ }
}
数据库操作
Room 支持协程:
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User) // 自动在 IO 线程执行
}
复杂任务组合
使用 flow 处理流式数据:
fun fetchDataFlow(): Flow<Data> = flow {
emit(loadFromCache())
emit(loadFromNetwork())
}.flowOn(Dispatchers.IO)
- 常见误区与优化
避免全局 GlobalScope
使用自定义作用域(如 lifecycleScope)防止内存泄漏。
合理选择调度器
Dispatchers.Main:UI 操作
Dispatchers.Default:CPU 密集型任务
Dispatchers.IO:磁盘/网络 I/O
异常处理
通过 CoroutineExceptionHandler 或 try/catch 捕获异常:
val handler = CoroutineExceptionHandler { _, e ->
Log.e("Coroutine", "Error: $e")
}
launch(handler) { /* 可能抛出异常的代码 */ }
总结
Kotlin 协程通过 挂起函数 和 结构化并发 将异步代码转为直观的同步风格,同时兼顾性能与安全性。掌握其核心概念(如作用域、调度器、状态机)后,可大幅提升 Android 或后端开发的效率。建议从官方文档的 Coroutines Guide 入手实践。