🧸 挂起函数 · 协程心脏

suspend · 定义 · 调用 · 机制
📌 suspend 关键字 & 挂起函数定义

🔖 suspend

Kotlin 中唯一让函数成为“可挂起”的修饰符。标记后,函数可以在协程内暂停执行而不阻塞线程。

suspend fun 名称()

📐 定义规则

• 必须使用 suspend 关键字
• 可以在挂起函数中调用其他挂起函数
• 不能从普通函数直接调用(需协程作用域)

🧩 典型例子

suspend fun fetchUser(): User {
    return withContext(Dispatchers.IO) {
        api.getUser()   // 模拟网络
    }
}
📞 挂起函数的调用 · 只能在协程内
调用场景示例说明
🌱 协程构建器launch { fetchUser() }最常用,在协程体内直接调用
🔁 另一个挂起函数suspend fun process() { fetchUser() }挂起函数可以自由调用其他挂起函数
⚡ suspend lambdasuspend { fetchUser() }通过 suspend 修饰的 lambda 表达式
🚫 普通函数fun main() { fetchUser() } ❌编译错误,必须提供协程环境
⏯️ 挂起与恢复机制 · 状态机魔法
线程 协程 A A' A B B' B C C' C 挂起点 (suspend) 恢复点 (resume) 挂起 (暂停, 不阻塞) 恢复 (继续执行)

⚙️ 状态机原理

  • 每个挂起函数被编译为状态机,每个挂起点对应一个状态。
  • 挂起时保存局部变量 + 状态编号,释放线程。
  • 恢复时根据状态编号跳转到正确位置,继续执行。
  • 线程不阻塞,可执行其他协程,极大提升资源利用率。
🧠 关键记忆

挂起 ≠ 阻塞
挂起 = 让出线程 + 保存状态
恢复 = 还原状态 + 继续执行

🧪 代码 · 挂起函数实战
// 定义挂起函数 —— 模拟耗时
// 使用 delay 挂起但不阻塞线程
suspend fun greetAfterDelay(name: String): String {
    delay(1000L)               // ⏳ 挂起点
    return "你好, $name!"
}

// 在 Compose / ViewModel 中调用
fun launchGreeting(scope: CoroutineScope) {
    scope.launch {
        val result = greetAfterDelay("小智")  // 挂起 ~1s
        println(result)                       // 恢复后打印
    }
}
对比挂起 (suspend)阻塞 (blocking)
线程释放线程,可被其他协程使用线程一直占用,不能做其他事
资源高效,支持高并发浪费,线程数有限
语法suspend 关键字 + 协程Thread.sleep() / 锁
Compose 中✅ 推荐,不卡UI❌ 会导致ANR