101.协程的基本用法 (Android)
协程启动:推荐在 Android 中使用 lifecycleScope 来启动协程,这样能在 Activity/Fragment 生命周期内自动取消协程任务,避免内存泄漏。线程切换:使用将耗时任务放入 IO 线程,处理完毕后返回主线程更新 UI。并发处理:使用async启动并发任务,通过await()获取结果,能提高执行效率。
·
1. 协程基本概念
协程(Coroutine)是用于简化异步编程的一种轻量级线程,能够帮助我们更简单地写出非阻塞UI代码。主要概念包括:
-
挂起函数(suspend function)
使用 suspend 修饰的函数可以在协程中挂起执行,而不会阻塞线程。 -
构建协程的作用域(Coroutine Scope)
协程必须在某个 CoroutineScope 中启动。Android 中常用的是 lifecycleScope 或 viewModelScope。 -
启动协程的方式
launch {}:启动一个协程,不关心返回结果。async {}:启动一个协程,同时返回一个Deferred<T>对象,可以调用await()获取结果。
-
调度器(Dispatchers)
Dispatchers.Main:在主线程运行,用于更新 UI。Dispatchers.IO:在 IO 线程运行,用于网络请求或数据库操作。Dispatchers.Default:用于计算任务。
2. 完整示例讲解
以下示例将展示如何在 Android Activity 中使用协程执行网络请求或者耗时操作,同时更新 UI。示例中使用了 lifecycleScope(需要依赖 AndroidX Lifecycle KTX)来管理协程,保证在生命周期结束时自动取消协程。
2.1 示例文件:MainActivity.kt
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* MainActivity 示例展示了如何使用 Kotlin 协程完成以下任务:
* 1. 使用 lifecycleScope 在主线程中启动协程。
* 2. 使用 withContext 切换到 IO 线程执行耗时操作。
* 3. 使用 async/await 并发执行任务并获取返回结果。
* 4. 更新 UI 或日志输出。
*/
/*
运行顺序:
启动协程,在主线程运行
启动并发任务
在IO线程中执行耗时操作
协程延时结束,更新UI
并发任务结果: 任务1完成, 任务2完成
从IO线程返回结果: 耗时操作结果
*/
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "MainActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 示例1: 在主线程中启动一个协程,延时后更新 UI
/*
lifecycleScope 是一个与 AndroidX Lifecycle 库集成的 Kotlin 协程作用域
它提供了一种便捷的方式来管理与 Android 组件(如 Activity 或 Fragment)生命周期相关的协程。
Coroutine Scope (协程作用域):
在 Kotlin 协程中,所有的协程都需要在一个作用域 (scope) 中启动
作用域控制着协程的生命周期。当一个作用域被取消时,它内部启动的所有协程也会被取消。
lifecycleScope 就是一个协程作用域,它与 Android 组件的生命周期相关联。
launch 是 Kotlin 协程库提供的一个函数,用于启动一个新的协程。
launch 函数返回一个 Job 对象,该对象代表正在运行的协程
你可以使用 Job 对象来取消协程、等待协程完成或获取协程的状态。
Job 对象代表一个正在执行的协程,它是一个可取消的、具有生命周期的后台任务。
Job 可以被看作是协程的句柄或引用。当你使用 launch 或 async 函数启动一个协程时,这些函数会返回一个 Job 对象。
你可以使用 Job 对象来控制协程的生命周期,例如取消协程、等待协程完成或获取协程的状态。
delay 是一个挂起函数。挂起函数只能在协程或另一个挂起函数中调用。
挂起函数可以暂停协程的执行,而不会阻塞线程。当挂起函数完成时,协程会自动恢复执行。
suspend 关键字用于声明一个挂起函数 (suspending function)
挂起函数是一种可以在协程中暂停执行,而不会阻塞线程的特殊函数。
*/
lifecycleScope.launch {
Log.d(TAG, "启动协程,在主线程运行")
// 延时 2 秒,模拟网络请求延时
delay(2000)
Log.d(TAG, "协程延时结束,更新UI")
// 这里可以更新UI,比如更新TextView的文本等
}
// 示例2: 切换到 IO 线程执行耗时操作并获取结果,再回到主线程更新UI
/*
withContext(Dispatchers.IO) 是一个挂起函数
用于在指定的协程上下文中执行一段代码块,并在代码块执行完成后自动恢复到原始的协程上下文。
withContext 函数允许你临时更改协程的上下文,并在代码块执行完成后自动恢复到原始的协程上下文。
*/
lifecycleScope.launch {
val result = withContext(Dispatchers.IO) {
Log.d(TAG, "在IO线程中执行耗时操作")
// 模拟耗时任务
delay(3000)
"耗时操作结果"
}
Log.d(TAG, "从IO线程返回结果: $result")
// 更新UI或处理结果
}
// 示例3: 使用 async/await 并发执行多个任务
/*
async(Dispatchers.IO) 是一个函数,用于在指定的协程上下文中异步启动一个新的协程
并返回一个 Deferred 对象,该对象代表异步计算的结果。
async 函数用于异步启动一个新的协程,并返回一个 Deferred 对象。
Deferred 对象是 Job 接口的子接口,它代表异步计算的结果。
await() 是 Deferred 接口提供的一个挂起函数。
await() 函数用于等待异步计算完成,并返回结果。
await() 函数只能在协程或另一个挂起函数中调用。
await() 函数会挂起当前协程,直到异步计算完成。
如果异步计算成功完成,await() 函数会返回异步计算的结果。
如果异步计算失败 (例如抛出异常),await() 函数会重新抛出该异常。
*/
lifecycleScope.launch {
Log.d(TAG, "启动并发任务")
// 启动并发任务
val deferredTask1 = async(Dispatchers.IO) {
delay(2000)
"任务1完成"
}
val deferredTask2 = async(Dispatchers.IO) {
delay(2500)
"任务2完成"
}
// 使用 await 获取结果
val result1 = deferredTask1.await()
val result2 = deferredTask2.await()
Log.d(TAG, "并发任务结果: $result1, $result2")
}
}
}
2.2 依赖说明
确保在你的项目中已经添加了协程和 lifecycle 的相关依赖。在 app 模块的 build.gradle 文件中添加类似如下依赖项:
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
// 其他依赖项
}
3. 教学总结
- 协程启动:推荐在 Android 中使用 lifecycleScope 来启动协程,这样能在 Activity/Fragment 生命周期内自动取消协程任务,避免内存泄漏。
- 线程切换:使用
withContext(Dispatchers.IO)将耗时任务放入 IO 线程,处理完毕后返回主线程更新 UI。 - 并发处理:使用
async启动并发任务,通过await()获取结果,能提高执行效率。
更多推荐

所有评论(0)