coroutines
kotlin的协程在kotlin1.3有了很大变化。。。
1. 协程的启动(building)
启动协程的主要两个方法
fun launch(): Job
fun async(): Deferred
1.1 launch
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
}
launch() 方法接收三个参数,通常很少用到第二个参数。
第一个参数是一个协程的上下文,
CoroutineContext
不仅可以用于在协程跳转的时刻传递数据,同时最主要的功能,是用于表明协程运行与恢复时的上下文环境。具体参数如下表
CoroutineDispatcher | --- | 对应的老版kotlin |
---|---|---|
Default | It is backed by a shared pool of threads on JVM. By default, the maximal number of threads used by this dispatcher is equal to the number CPU cores, but is at least two. | CommonPool |
Main | A coroutine dispatcher that is confined to the Main thread operating with UI objects. | UI |
Unconfined | It executes initial continuation of the coroutine immediately in the current call-frame and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without mandating any specific threading policy. | Unconfined |
IO | The [CoroutineDispatcher] that is designed for offloading blocking IO tasks to a shared pool of threads. |
老版本的协程,通常
Android
在用的时候都是传一个UI
就表示在 UI 线程启动协程,或者传一个CommonPool
表示在异步启动协程,还有一个是Unconfined
表示不指定,在哪个线程调用就在哪个线程恢复。
public fun launch(
context: CoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
}
// CoroutineContext, 不仅可以用于在协程跳转的时刻传递数据,同时最主要的功能,是用于表明协程运行与恢复时的上下文环境。
1.2 async()方法
async()
方法也是创建一个协程并启动,甚至连方法的声明都跟launch()
方法一模一样。
不同的是,async()
方法的返回值,返回的是一个Deferred
对象。这个接口是Job
接口的子类。
因此上文介绍的所有方法,都可以用于Deferred
的对象。
Deferred
最大的用处在于他特有的一个方法await()
:
public suspend fun await(): T
await()
可以返回当前协程的执行结果,也就是你可以这样写代码:
fun main(){
runBlocking {
val deferred1 = async(Dispatchers.Default) {
println(Thread.currentThread())
"hello1"
}
async(Dispatchers.Default){
println(Thread.currentThread())
println("hello2")
println(deferred1.await())
}
}
}
你发现神奇的地方了吗,我让一个工作在主线程的协程,获取到了一个异步协程的返回值。
这意味着,我们以后网络请求、图片加载、数据库、文件操作什么的,都可以丢到一个异步的协程中去,然后在同步代码中直接取返回值,而不再需要去写回调了。
这就是我们经常使用的一个最大特性。
Question
如果采用 GlobalScope启动协程会怎么样?
fun main(){
runBlocking {
val deferred1 = async(Dispatchers.Default) {
println(Thread.currentThread())
"hello1"
}
async(Dispatchers.Default){
println(Thread.currentThread())
println("hello2")
println(deferred1.await())
}
}
}
// 运行结果
Thread[DefaultDispatcher-worker-1,5,main]
Thread[DefaultDispatcher-worker-3,5,main]
hello2
hello1