0Pricing
Android Academy · 课时

协程与挂起函数

编写读起来像同步代码一样的异步代码。使用挂起函数、协程作用域和调度器(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 反馈 — 无需本地设置。

此课程中的所有课时

  1. ViewModel 与 LiveData
  2. Room 数据库
  3. 协程与挂起函数
  4. 仓储模式
  5. Navigation 组件
  6. 使用 Hilt 进行依赖注入
← 返回 Android Academy