协程是什么?
协程作用域(CoroutineScope)是什么?
在 Android 中如何用协程(尤其是生命周期绑定)?
我们来从底层原理 → 语法机制 → Android 实践 三层讲清楚。
🧩 一、协程是什么?
一句话总结:
协程是一种轻量级的线程(更准确说是线程上的可挂起任务) ,
能在一个线程中挂起、恢复执行,让异步代码像同步一样写。
✅ 举个最通俗的例子:
不用协程(传统写法):
kotlin
Thread {
val data = loadFromNetwork()
runOnUiThread {
showData(data)
}
}.start()
用协程:
kotlin
lifecycleScope.launch {
val data = withContext(Dispatchers.IO) {
loadFromNetwork()
}
showData(data)
}
👉 逻辑完全一样,但写法更直观,没有回调地狱。
协程可以在同一线程中**挂起(suspend)**执行异步任务,待任务完成后自动恢复。
🧠 二、协程的本质
协程 ≠ 线程。
协程是 运行在某个线程上的任务调度单元 ,由协程调度器(Dispatcher)管理。
| 对比项 | 线程(Thread) | 协程(Coroutine) |
|---|---|---|
| 创建成本 | 高(1MB 栈空间) | 低(几 KB) |
| 切换成本 | 系统级上下文切换 | 用户态调度(轻量) |
| 异步写法 | 回调或线程池 | 同步结构(挂起) |
| 生命周期 | 操作系统管理 | Kotlin 代码层管理 |
⚙️ 三、协程作用域(CoroutineScope)
作用域(Scope) 决定了:
- 协程在哪个上下文(线程)中运行;
- 协程的生命周期;
- 异常取消策略。
✅ 1️⃣ 常见作用域类型
| 作用域 | 用途 | 生命周期 |
|---|---|---|
GlobalScope |
全局协程,不推荐 | 应用进程 |
lifecycleScope |
Android Activity / Fragment 绑定 |
随生命周期结束自动取消 |
viewModelScope |
Android ViewModel 绑定 |
ViewModel 销毁时取消 |
CoroutineScope |
自定义作用域 | 由开发者控制取消 |
✅ 2️⃣ 示例:自定义作用域
kotlin
class MyRepository {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
fun fetchData() {
scope.launch {
val data = loadDataFromNetwork()
println(data)
}
}
fun clear() {
scope.cancel() // 主动取消
}
}
🧩 四、在 Android 中如何使用协程
✅ 1️⃣ Activity / Fragment 中使用
绑定生命周期 → 用 lifecycleScope
kotlin
lifecycleScope.launch {
val user = withContext(Dispatchers.IO) { getUser() }
updateUI(user)
}
当 Activity 销毁时,
lifecycleScope会自动取消协程,避免内存泄漏。
✅ 2️⃣ ViewModel 中使用
绑定 viewModelScope,协程自动随 ViewModel 销毁而取消:
kotlin
class UserViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch {
val user = withContext(Dispatchers.IO) { getUserFromDb() }
_userLiveData.value = user
}
}
}
👉 这是最标准的 Android 架构写法。
✅ 3️⃣ Repository 层
通常是挂起函数 + IO 调度:
kotlin
class UserRepository {
suspend fun getUser(): User {
return withContext(Dispatchers.IO) {
apiService.getUser()
}
}
}
调用端(ViewModel):
kotlin
viewModelScope.launch {
val user = repository.getUser()
}
✅ 4️⃣ 常用调度器(Dispatchers)
| 调度器 | 用途 | 对应线程池 |
|---|---|---|
Dispatchers.Main |
UI 操作 | 主线程 |
Dispatchers.IO |
网络 / 文件 / 数据库 | IO 线程池 |
Dispatchers.Default |
CPU 密集计算 | 默认线程池 |
Dispatchers.Unconfined |
不固定线程 | 测试或特殊情况 |
🧠 五、协程关键语法
1️⃣ launch
启动一个协程,不返回结果(类似 fire-and-forget):
kotlin
launch {
doSomething()
}
2️⃣ async / await
启动并返回结果:
kotlin
val result = async { getData() }
println(result.await())
3️⃣ withContext
切换线程并返回结果:
kotlin
val data = withContext(Dispatchers.IO) { loadFromDb() }
4️⃣ suspend
标记挂起函数(可在协程中调用):
kotlin
suspend fun getData(): String {
delay(1000) // 模拟耗时操作
return "OK"
}
🧩 六、协程异常与取消
✅ 异常捕获
kotlin
viewModelScope.launch {
try {
val data = repository.getData()
} catch (e: Exception) {
Log.e("TAG", "error: $e")
}
}
✅ 取消协程
kotlin
val job = launch {
repeat(1000) {
delay(100)
println("Working $it")
}
}
delay(500)
job.cancel() // 协程被取消
🔥 七、面试速答总结
Kotlin 协程是基于挂起函数的轻量级异步方案,能让异步代码以同步形式书写。
协程运行在作用域中,作用域决定协程的生命周期和调度线程。
在 Android 中:
- Activity / Fragment 用
lifecycleScope- ViewModel 用
viewModelScope- 数据层使用挂起函数 + IO 调度
协程底层通过Continuation对象恢复挂起点,实现非阻塞线程的异步执行。