我最近潜入Kotlin协同程序因为我使用了很多Google的库,所以大部分工作都是在Task类中完成的
目前我正在使用此扩展来暂停协程
suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
task.addOnCompleteListener { task ->
if (task.isSuccessful) {
continuation.resume(task.result)
} else {
continuation.resumeWithException(task.exception!!)
}
}
}
但最近我见过这样的用法
suspend fun <T> awaitTask(task: Task<T>): T = suspendCoroutine { continuation ->
try {
val result = Tasks.await(task)
continuation.resume(result)
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
有什么区别,哪一个是正确的?
UPD:第二个例子不起作用,idk为什么
传递给suspendCoroutine { ... }
的代码块不应该阻止它被调用的线程,允许协程被挂起。这样,实际线程可以用于其他任务。这是一个关键功能,允许Kotlin协程扩展并在单个UI线程上运行多个协同程序。
第一个例子是正确的,因为它调用task.addOnCompleteListener
(see docs)(它只是添加一个监听器并立即返回。这就是为什么第一个正常工作的原因。
第二个示例使用Tasks.await(task)
(see docs)来阻止它被调用的线程,并且在任务完成之前不会返回,因此它不允许协程正确挂起。
您的第二个示例是更传统的阻止功能。
在典型的Java多线程世界中,您使用类似的函数来阻塞线程,直到结果返回。
同样在典型的Java中,有一种称为Reactive programming的新范例,它允许您在结果返回之前避免阻塞线程。您可以提供一个在结果到达时执行的第一类函数,而不是仅仅等待结果。这样,暂停时没有留下线程;相反,只有一个新事件附加到运行长操作的线程上,当操作完成时,该事件将触发。
阻塞:
Thread one: --* . . . ./---
Thread two: \------*
反应:
Thread one: --* (now free)
Thread two: \-------*---
如果你研究反应式编程,你会发现更好的解释,深入探讨。
回到你的问题,这两种看似相同的方式是Java范式转变的结果。当然,由于我们在这里与Coroutines合作,我们根本不必担心阻塞问题;语言通过暂停而不是阻止来处理它。因此,反应性编程的许多优点在语言层面上得到了解决。
然而,范式仍然有其优点,所以即使它不像其他地方那样严格必要,看到人们继续以这种模式工作也是有道理的。