Kotlin---协程的使用
2019-01-09 本文已影响21人
None_Ling
第一个协程
在使用协程之前,需要保证Kotlin-Gradle-Plugin
的版本高于1.3。目前最高的版本为1.3.11。否则编译会报错
首先来创建一个协程:
GlobalScope.launch { // 在后台启动一个新的协程并继续
delay(1000L) // 非阻塞的等待 1 秒钟(默认时间单位是毫秒)
println("World!...${Thread.currentThread().name}") // 在延迟后打印输出
}
println("Hello,...${Thread.currentThread().name}") // 协程已在等待时主线程还在继续
而打印出的结果为:
Hello,...main
World!...DefaultDispatcher-worker-1 @coroutine#1
可以看到通过GlobalScope.launch
完成了:
- 启动了新的线程,在该线程中创建了一个协程
@coroutine#1
- 在该协程中
delay(1000L)
等待了1秒后再输出日志。 - 并且这样执行的协程,并不会阻塞主线程的执行
delay
函数只能在协程中使用,否则编译不过,尽量避免使用GlobalScope.launch
创建协程,当我们使用 GlobalScope.launch 时,我们会创建一个顶层协程。虽然它很轻量,但它运行时仍会消耗一些内存资源。如果我们忘记保持对新启动的协程的引用,它还会继续运行。
阻塞的协程runBlocking
GlobalScope.launch
启动了一个线程创建新的协程,并没有阻塞当前线程。而如果想要在当前线程创建协程的话,则需要使用runBlocking
runBlocking {
launch {
Log.e(TAG,"${Thread.currentThread().name}...start delay 2000L")
delay(2000L)
Log.e(TAG,"${Thread.currentThread().name}...delay 2000L")
}
launch {
Log.e(TAG,"${Thread.currentThread().name}...start delay 4000L")
delay(4000L)
Log.e(TAG,"${Thread.currentThread().name}...delay 4000L")
}
Log.e(TAG,"${Thread.currentThread().name}...launch 2 coroutines")
}
从输出结果,可以看到:
- 直接在
runBlocking
中调用delay()
会阻塞当前线程 - 在
runBlocking
中调用launch()
会开启新的协程,并且不会阻塞当前线程 - 在
runBlocking
中调用launch()
会在当前线程中执行协程
main @coroutine#1...launch 2 coroutines
main @coroutine#2...start delay 2000L
main @coroutine#3...start delay 4000L
main @coroutine#2...delay 2000L
main @coroutine#3...delay 4000L
等待协程执行完毕
无论通过GlobalScope.launch
还是runBlocking
中的launch
,都会返回一个Job
对象。通过Job.join
函数,可以等待协程执行完毕再继续执行。
val job = GlobalScope.launch { // 启动一个新协程并保持对这个作业的引用
delay(1000L)
println("Hello,...${Thread.currentThread().name}")
}
job.join() // 等待直到子协程执行结束
println("World!...${Thread.currentThread().name}")
输出结果:
Hello,...DefaultDispatcher-worker-1 @coroutine#2
World!...main @coroutine#1
CoroutineScope作用域
在runBlocking
中可以定义一个coroutineScope
,而该函数的作用是为在这个函数中启动的协程添加作用域,只有当作用域内的协程都执行完毕后,才会继续执行当前线程。
runBlocking {
Log.e(TAG, "${Thread.currentThread().name}...$this...start coroutineScope")
coroutineScope {
launch {
delay(4000L)
Log.e(TAG, "${Thread.currentThread().name}...$this...start delay 4000L")
}
launch {
delay(3000L)
Log.e(TAG, "${Thread.currentThread().name}...$this...start delay 3000L")
}
}
Log.e(TAG, "${Thread.currentThread().name}...$this...after launch ")
}
输出的结果:
01-09 17:03:39.972 main...BlockingCoroutine{Active}@3fc800e3...start coroutineScope
01-09 17:03:39.972 main...StandaloneCoroutine{Active}@2affbae0...start delay 3000L
01-09 17:03:42.982 main...StandaloneCoroutine{Active}@23130199...start delay 4000L
01-09 17:03:43.982 main...BlockingCoroutine{Active}@3fc800e3...after launch
可以看到,在最后的日志打印之前,会等待coroutineScope
中的协程都执行完毕后,才会继续执行
挂起函数
当协程中的代码超级多的时候,通常都会把这些代码提取到一个函数中。但是这个函数必须使用suspend
标识,否则编译错误,并且无法调用协程中到函数,比如delay()
。
- 使用
suspend
标示的函数只能用于协程中,无法在其他函数中被调用
import kotlinx.coroutines.*
fun main() = runBlocking {
launch { doWorld() }
println("Hello,")
}
// 你的第一个挂起函数
suspend fun doWorld() {
delay(1000L)
println("World!")
}