Kotlin协程基础
协程是轻量级的线程
一、android导包
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8"
}
repositories {
jcenter()
}
二、基础
GlobalScope.launch启动新的协程
runBlocking 阻塞线程
fun main() {
GlobalScope.launch { //在后台启动⼀个新的协程并继续
delay(1000L) //delay是⼀个特殊的挂起函数 ,它不会造成线程阻塞,会挂起协程,并且只能在协程中使用
println("World!")
}
println("Hello,")
runBlocking { //这个表达式阻塞了主线程
delay(2000L)
}
}
三、结构化的并发
可以在执行操作所在的指定作用域内启动协程,而不是像通常使用线程(线程总是全局的)那样在 GlobalScope 中启动。
每个协程构建器都将 CoroutineScope 的实例添加到其代码块所在的作用域中。我们可以在这个作用域中启动协程而无需显式 join ,因为外部协程直到在其作用域中启动的所有协程都执行完毕后才会结束
fun main() = runBlocking {
val job = GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
job.join() // 等待直到子协程执行结束
}
fun main() = runBlocking { // this: CoroutineScope
launch { // 在 runBlocking 作⽤域中启动⼀个新协程
delay(1000L)
println("World!")
}
println("Hello,")
}
四、作用域构建器
除了由不同的构建器提供协程作用域之外,还可以使用 coroutineScope 构建器声明自己的作用域。它会创建⼀个协程作用域并且在所有已启动子协程执行完毕之前不会结束。
runBlocking 与 coroutineScope 可能看起来很类似,因为它们都会等待其协程体以及所有子协程结束。主要区别在于,runBlocking 方法会阻塞当前线程来等待,而 coroutineScope 只是挂起,会释放底层线程用于其他用途。由于存在这点差异,runBlocking 是常规函数,而 coroutineScope 是挂起函数。
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("MainActivity Task from runBlocking")
}
coroutineScope { // 创建⼀个协程作⽤域
launch {
delay(500L)
println("MainActivity Task from nested launch")
}
delay(100L)
println("MainActivity Task from coroutine scope") // 这⼀行会在内嵌 launch 之前输出
}
println("MainActivity Coroutine scope is over") // 这⼀行在内嵌 launch 执行完毕后才输出
}
五、提取函数重构
协程里边的代码。提取出函数,可以用suspend 修饰符来修饰,成为挂起函数。可以像正常函数一样,在协程内部被调用。特性是内部还可以使用其它挂起函数,如delay()
提取出的函数包含⼀个在当前作⽤域中调⽤的协程构建器,提取函数 上只有 suspend 修饰符是不够的
- 为 CoroutineScope 写⼀个 doWorld 扩展方法
- 显式将 CoroutineScope 作为包含该函数的类的⼀个字段
- 当外部类实现了 CoroutineScope 时隐式取得
六、协程很轻量
相比线程,创建大量的协程,都不会内存不足
七、全局协程像守护线程
在 GlobalScope 中启动了⼀个长期运行的协程,该协程每秒输出“I'm sleeping”两次,之后在主函数中延迟⼀段时间后返回。
GlobalScope.launch {
repeat(1000) { i ->
println("MainActivity I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // 在延迟后退出
它输出了以下三行后终止。在 GlobalScope 中启动的活动协程并不会使进程保活。它们就像守护线程。