在本文中,我们将学习Kotlin协程中的“launch”和“async”的区别,以及何时使用它们。
“launch”和“async”都是在Kotlin中启动协程的函数。
launch{}
async{}
它们之间的不同之处在于,“launch{}”返回一个“Job”对象,不传递任何结果值,而“async{}”返回一个“Deferred”实例,它有一个“await()”函数,返回协程的结果,就像Java中的Future一样,在其中我们使用future.get()来获取结果。
换句话说:
- “launch”:启动并忘记。
- “async”:执行任务并返回结果。
让我们拿一个例子来学习“launch”和“async”的区别。
我们可以如下使用“launch”:
val job = GlobalScope.launch(Dispatchers.Default) {
// do something and do not return result
}
“launch”返回一个“Job”对象,我们可以使用它来获取任务的状态或取消任务执行。
在上面“launch”的例子中,我们需要做某些事情,但不需要将结果返回。
但是,当我们需要返回结果时,我们需要使用“async”。
val deferredJob = GlobalScope.async(Dispatchers.Default) {
// do something and return result, for example 10 as a result
return@async 10
}
val result = deferredJob.await() // result = 10
接下来,我们将使用await()获取结果。
在“async”中,我们也可以使用Deferred job对象来获取任务的状态或取消它。
注意:我在快速示例中使用了GlobalScope,我们应该尽量避免使用它。在Android项目中,我们应该根据我们的用例使用自定义范围,如lifecycleScope、viewModelScope等。
“launch”和“async”的另一个区别是异常处理。
如果在“launch”块中出现任何异常,如果我们没有处理它,则会导致应用程序崩溃。
但是,如果在“async”块中出现任何异常,则它将存储在生成的“Deferred”中,并且不会传递到其他任何地方,它将被默默地丢弃,除非我们对其进行处理。
让我们通过代码示例理解这个区别。
假设我们有一个函数执行某个操作并抛出异常:
private fun doSomethingAndThrowException() {
throw Exception("Some Exception")
}
现在我们使用“launch”调用它:
GlobalScope.launch {
doSomethingAndThrowException()
}
如预期的那样,这将导致应用程序崩溃。
我们可以通过以下方式处理它:
GlobalScope.launch {
try {
doSomethingAndThrowException()
} catch (e: Exception) {
// handle exception
}
}
现在,异常将进入catch块,我们可以处理它。
现在我们使用“async”调用它:
GlobalScope.async {
doSomethingAndThrowException()
}
应用程序不会崩溃。异常将被静默地丢弃。
同样,我们可以通过以下方式处理它:
GlobalScope.async {
try {
doSomethingAndThrowException()
} catch (e: Exception) {
// handle exception
}
}
现在,异常将进入catch块,我们可以处理它。
让我总结一下“launch”和“async”的区别:
Launch | Async |
---|---|
Fire and forget. | 执行任务并返回结果 |
– | – |
launch{}返回一个Job,不携带任何结果值。 | async{}返回一个Deferred的实例,它有一个await()函数来返回coroutine的结果。 |
– | – |
如果在启动块中出现任何异常,如果我们没有处理它,就会使应用程序崩溃。 | 如果任何异常出现在异步块内,它将被存储在产生的递延内,不会被传递到其他地方,除非我们处理它,否则它将被默默地丢弃。 |
所以,我们已经了解了启动函数和异步函数之间的区别。