kotlin 协程的用法

协程是什么?

协程作用域(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. 协程在哪个上下文(线程)中运行;
  2. 协程的生命周期;
  3. 异常取消策略。

✅ 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 对象恢复挂起点,实现非阻塞线程的异步执行。

相关推荐
DCTANT3 小时前
【原创】使用更优雅的方式改造MyBatisPlus逻辑删除插件
spring boot·后端·mysql·kotlin·mybatis·mybatisplus
lynn8570_blog3 小时前
关于compose的remember
android·kotlin
冬奇Lab6 小时前
【Kotlin系列04】类与对象基础:从Java Bean到Data Class的优雅蜕变
android·kotlin·编程语言
撩得Android一次心动6 小时前
Android Lifecycle 全面解析:掌握生命周期管理的艺术(1)
android·java·kotlin·lifecycle
yeziyfx18 小时前
kotlin中 ?:的用法
android·开发语言·kotlin
Kapaseker1 天前
千锤百炼写View 摸爬滚打名声就
android·kotlin
zFox2 天前
四、ViewModel + StateFlow + 状态持久化
kotlin·stateflow·viewmodel