使用 withContext 返回值
大约 2 分钟
现在您可以使用抽象的 API 在线程和调度器之间切换,是时候学习另外一个协程构建器:withContext
。
它允许您通过挂起的方式从另一个 CoroutineContext 返回一个值。如前所述,您将在本书后面章节了解更多有关上下文的信息,但这是了解另一个有用的挂起函数比较好的切入点。
关于挂断函数和协程,其中有一个非常重要的点就是它们不会阻塞正在运行的线程。这意味着每当您在协程中并调用挂起函数时,它将暂停协程,而不是阻塞线程。我们已经讨论了几次,但让我们看看它在实践中是如何工作的。
将 Main.kt 的内容替换为以下代码:
fun main() {
GlobalScope.launch(Dispatchers.Main) { // 1
val user = getUserSuspend("101") // 2
println(user) // 4
}
}
// 3
suspend fun getUserSuspend(userId: String): User =
withContext(Dispatchers.Default) {
delay(1000)
User(userId, "Filip")
}
上面的代码片段与您前面使用的非常相似,但是有一个比较大的区别。上面的代码处理线程和调度器的方式与前面的相反。
与其在后台启动协程,然后将数据再推送到主线程,不如执行相反的操作——在主线程上启动协程,然后将数据获取推送到后台。这种方式非常符合直觉,同时也展示了使用 withContext
桥接主线程和后台线程是多么容易。
上面代码片段的可能执行以下四个步骤:
- 您在主线程启动了一个协程,同时将协程的作用域限定为主线程。
- 通过调用挂起函数,您可以释放主线程以进行其他工作,直到数据准备好了。
- 在
getUserSuspend
内,您使用withContext(Dispatchers.Default)
来获取user
,同时确保本次操作运行在一个不同的后台线程。 - 当
user
数据返回时,您就可以输出它了。
这确实展示了使用协程编写良好且顺序的代码非常容易,同时这些协程仍然可以顺利运行并且不会导致任何 UI 冻结。