一、前言
虽然之前已经讲了两篇协程,不过本篇还是协程基础。本篇主要是从kotlin官网上了解的关于协程的相关内容
二、相关依赖
如果只是使用协程的话,可以使用下面的依赖。下面的库并不依赖于Android环境:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-//android:1.5.1' android上则需要改为这个依赖项
}
buildscript {
ext.kotlin_version = '1.5.20'
}
repository {
mavenCentral()
}
三、runBlocking和coroutineScope
有时候我们会看到这两个函数,根据官方介绍,runBlocking会阻塞当前线程等待,coroutineScope会挂起释放底层线程用作他用。用以下来解释他们的区别
首先看runBlocking
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
// assertEquals(4, 2 + 2)
testCoroutines()
}
private fun testCoroutines(){
println("000000")
runBlocking {
delay(1000)
println("11runBlocking")
}
println("22222")
}
}
运行后可以看到以下结果
000000
11runBlocking
22222
Process finished with exit code 0
我们再看coroutineScope
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
// assertEquals(4, 2 + 2)
GlobalScope.launch {
testCoroutines()
}
}
private suspend fun testCoroutines(){
println("000000")
coroutineScope {
delay(1000)
println("11runBlocking")
}
println("22222")
}
}
首先可以发现testCoroutines()
中多了一个suspend
的挂起修饰符。其次需要用GlobalScope.launch {}
包括该函数。说明runBlocking
自己就有作用域,而coroutineScope
没有,而且这是一个挂起函数,需要被其它挂起函数或者协程启动。然后我们看运行结果
Process finished with exit code 0
会发现什么都没有(因为程序执行完了,所以里面东西没有打印就不打印了),这时候我们明白了,为什么runBlocking
是阻塞线程,而coroutineScope
是挂起函数,没有阻塞线程。
四、为什么runBlocking可以直接启动协程
当launch
、async
、 或runBlocking
用于启动新的协程时,它们会自动创建相应的作用域。所有这些函数都以一个带有接收器的 lambda 作为参数,隐式接收器类型是CoroutineScope
:
launch{ /* this: CoroutineScope */
}
新的协程只能在一个范围内启动。 launch
并且async
被声明为对 的扩展CoroutineScope
,因此当我们调用它们时必须始终传递隐式或显式接收器。由启动的协程runBlocking
是唯一的例外:runBlocking
被定义为顶级函数。但是因为它阻塞了当前线程,所以它主要用于main
函数和测试中作为桥接函数。
五、launch、async
启动协程有两个方式,通过launch或者async。
通常,您应使用 launch
从常规函数启动新协程,因为常规函数无法调用 await
。只有在另一个协程内时,或在挂起函数内且正在执行并行分解时,才使用 async
。
警告:launch
和 async
处理异常的方式不同。由于 async
希望在某一时刻对 await
进行最终调用,因此它持有异常并将其作为 await
调用的一部分重新抛出。这意味着,如果您使用 async
从常规函数启动新协程,则能以静默方式丢弃异常。这些丢弃的异常不会出现在崩溃指标中,也不会在 logcat 中注明。如需了解详情,请参阅协程中的取消和异常。
如下方式才是对协程的启动
private fun testCoroutines(){
println("000000")
runBlocking {
launch {
delay(1000)
println("11runBlocking---launch")
}
async {
delay(1000)
println("11runBlocking---async")
}
println("11runBlocking---end")
}
println("22222")
}