跳至主要內容

使用 withContext 返回值

guodongAndroid大约 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 桥接主线程和后台线程是多么容易。

上面代码片段的可能执行以下四个步骤:

  1. 您在主线程启动了一个协程,同时将协程的作用域限定为主线程。
  2. 通过调用挂起函数,您可以释放主线程以进行其他工作,直到数据准备好了。
  3. getUserSuspend 内,您使用 withContext(Dispatchers.Default) 来获取 user,同时确保本次操作运行在一个不同的后台线程。
  4. user 数据返回时,您就可以输出它了。

这确实展示了使用协程编写良好且顺序的代码非常容易,同时这些协程仍然可以顺利运行并且不会导致任何 UI 冻结。