协程与挂起函数
编写读起来像同步代码一样的异步代码。使用挂起函数、协程作用域和调度器(IO、Main、Default)。
协程与挂起函数 是 CoddyKit 上的免费 Android Academy 课时。 这是第 3 节课,共 6 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 6 节课。
问题:阻塞界面线程
Android 会在主线程上运行所有界面工作。如果您在主线程上执行网络请求或数据库读取,界面会一直冻结,直到操作完成。
如果界面冻结超过 5 秒,Android 会显示 ANR(应用无响应)对话框,用户可以强制关闭应用。
什么是协程?
Kotlin 协程是一种编写异步代码的方式,使代码看起来像按顺序执行,无需回调,也无需 RxJava 链。
- 轻量:可以并发运行数千个协程
- 可挂起:协程可以暂停和恢复,而不会阻塞线程
- 结构化:协程会遵循生命周期(作用域)
suspend 函数
使用 suspend 标记的函数可以暂停执行而不会阻塞线程。它只能从另一个挂起函数或协程作用域中调用。
import kotlinx.coroutines.*
suspend fun fetchData(): String {
delay(1000) // simulates 1 second network call
return "Data loaded!"
}
fun main() = runBlocking {
println("Fetching...")
val result = fetchData() // suspends here, doesn't block
println(result) // Data loaded!
println("Done")
}协程作用域
每个协程都在定义其生命周期的作用域中运行:
viewModelScope— ViewModel 被清除时取消lifecycleScope— Activity/Fragment 被销毁时取消GlobalScope— 永久存在(请避免使用)runBlocking— 仅用于测试
launch 与 async
启动协程的两种方式:
launch { }— 启动后不等待,不返回值async { }.await()— 返回一个可以等待其结果的值
import kotlinx.coroutines.*
fun main() = runBlocking {
// launch: no return value
launch {
delay(500)
println("launch done")
}
// async: returns a Deferred<T>
val deferred = async {
delay(300)
42
}
val result = deferred.await()
println("async result: $result")
}Dispatchers:使用哪个线程?
Dispatchers 控制协程运行在哪个线程上:
Dispatchers.Main— UI 线程(用于更新视图)Dispatchers.IO— 用于网络和磁盘操作Dispatchers.Default— 用于 CPU 密集型任务
在协程内部使用 withContext(Dispatchers.IO) { } 切换调度器。
viewModelScope 示例
在 ViewModel 中获取数据,同时不阻塞 UI:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
class DataViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// Switch to IO thread for network
val data = withContext(Dispatchers.IO) {
// simulate network request
delay(1000)
"Result from server"
}
// Back on Main thread — safe to update UI
_uiState.value = data
}
}
}协程中的错误处理
使用 try/catch 在协程内部处理异常,就像处理普通代码一样:
viewModelScope.launch {
try {
val result = withContext(Dispatchers.IO) {
api.fetchUser() // may throw IOException
}
_user.value = result
} catch (e: Exception) {
_error.value = "Failed: ${e.message}"
}
}并行运行协程
使用 async/await 并行运行两个任务,并等待它们全部完成:
viewModelScope.launch {
// Both run at the same time!
val userDeferred = async(Dispatchers.IO) { api.getUser() }
val postsDeferred = async(Dispatchers.IO) { api.getPosts() }
val user = userDeferred.await()
val posts = postsDeferred.await()
_state.value = UiState(user, posts)
}快速检查
对于网络和数据库操作,应该使用哪个协程调度器?
回顾:协程
现在您可以编写不依赖回调的异步代码:
suspend fun— 可以暂停而不会阻塞线程viewModelScope.launch { }— 在 ViewModel 中启动协程withContext(Dispatchers.IO)— 切换到后台线程async { }.await()— 执行并行任务并获取结果- try/catch 在协程内部也能正常工作
下一节:Repository 模式——在数据源之间实现清晰分离。
常见问题解答
「协程与挂起函数」课时是免费的吗?
是的 — 「协程与挂起函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 6 节课。
「协程与挂起函数」这节课中我会学到什么?
编写读起来像同步代码一样的异步代码。使用挂起函数、协程作用域和调度器(IO、Main、Default)。 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 6 节。
「协程与挂起函数」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。