Kotlin协程入门:让异步编程更简单
你有没有写过这样的代码:从网络请求数据,等结果回来再更新界面,接着又去读本地文件,每一步都得套一层回调?时间一长,代码像洋葱一样层层嵌套,看得人头晕。在Android开发或者基于JVM的后台服务中,这类问题尤其常见。Kotlin协程就是来解决这个痛点的。
协程不是线程,也不是新发明的概念,但它让异步操作写起来像写同步代码一样直观。你可以用看似“顺序执行”的方式处理耗时任务,而不必陷入回调地狱。
协程是什么?
想象你在煮泡面:烧水的时候你不用干站着,可以顺便切点火腿、拿碗筷。程序里也一样,协程允许你在等待某个操作(比如网络请求)完成时,先去执行别的任务,等结果到了再回来继续。它比开启多个线程更轻量,启动一个协程的开销远小于创建一个线程。
在Kotlin中,协程是语言层面的支持,通过库的形式提供,核心是kotlinx.coroutines。
第一个协程例子
在你的项目中引入依赖:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'然后写一段简单的代码:
import kotlinx.coroutines.*
fun main() {
println("开始")
runBlocking {
launch {
delay(1000L)
println("协程打印:你好")
}
println("非阻塞语句")
}
println("结束")
}输出结果是:
开始
非阻塞语句
协程打印:你好
结束这里runBlocking会阻塞主线程直到内部所有协程完成,launch启动了一个新的协程,delay(1000L)模拟耗时操作,但它不会像Thread.sleep()那样阻塞整个线程。
用async获取返回值
有时候你需要拿到异步操作的结果。比如同时请求用户信息和订单列表,等两者都完成后再展示页面。这时候可以用async:
runBlocking {
val user = async { fetchUser() }
val orders = async { fetchOrders() }
println("用户:${user.await()},订单数:${orders.await().size}")
}
suspend fun fetchUser(): String {
delay(800L)
return "zhangsan"
}
suspend fun fetchOrders(): List<String> {
delay(1200L)
return listOf("订单1", "订单2")
}suspend关键字标记的函数只能在协程中调用,它们可以在不阻塞线程的情况下挂起和恢复。这正是协程的核心机制。
Android中的实际应用
在Android里,你通常不能在主线程做网络请求。以前的做法是开子线程,完成后切回主线程更新UI。现在可以这样写:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 启动协程
lifecycleScope.launch {
try {
val data = withContext(Dispatchers.IO) {
fetchDataFromNetwork()
}
textView.text = data
} catch (e: Exception) {
textView.text = "加载失败"
}
}
}
private suspend fun fetchDataFromNetwork(): String {
delay(2000L)
return "从网络获取的数据"
}
}这里lifecycleScope绑定了Activity的生命周期,协程会自动在页面销毁时取消,避免内存泄漏。withContext(Dispatchers.IO)切换到IO线程执行耗时操作,而赋值给TextView的操作则自动回到主线程。
代码清晰,逻辑连贯,没有来回切换线程的混乱感。
取消协程:别忘了收尾
协程可以被取消。比如用户打开页面还没加载完就退出了,正在执行的请求应该停止。调用job.cancel()就能中断协程,但前提是协程能响应取消信号。
使用ensureActive()或定期调用可挂起函数(如yield()、delay())都能触发检查。如果协程已经被取消,就会抛出CancellationException。
协程不是万能药,但它是现代Kotlin开发中处理异步任务的首选方式。上手门槛低,效果立竿见影。试试把旧项目里的回调换成协程,你会发现代码一下子清爽了。