Kotlin协程
有些 APIs 是需要长时间运行,并且需要调用者阻塞直到这些调用完成(比如网络 IO ,文件 IO ,CPU 或者 GPU 比较集中的工作)。协程提供了一种避免线程阻塞并且用一种更轻量级,更易操控到操作:协程暂停。
添加Kotlin协程依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"
1、挂起函数
当一个函数被 suspend
修饰时表示可以被挂起,调用它会导致挂起协程,挂起函数可以和正常函数那样接受参数返回结果,但只能在协程中调用或着被其他挂起函数调用。
suspend fun doSomething(){
//do something
delay(1000)
}
因为delay为Kotlin封装的挂起函数,所以调用delay的函数也必须是挂起函数。
2、协程Api
在已有的Api中,Kotlin提供了两种方式实现协程 async/Deferred和launch/Job
public actual fun <T> async(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
val newContext = newCoroutineContext(context, parent)
val coroutine = if (start.isLazy)
LazyDeferredCoroutine(newContext, block) else
DeferredCoroutine<T>(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
public expect fun launch(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> Unit
): Job
从源码中可以看出async和launch的参数列表中只有最后一个参数:带有 suspend
修饰的函数类型不同,async中的lambda有返回值,和Deferred的类型相同。launch中的lambda没有返回值。
async(UI) {
val deferred = async(CommonPool) {
//do something
delay(1000)
"stop"
}
deferred.await()
}
3、context
两个Api的构造函数中,第一个参数为context。在android开发中比较常用的两个为UI何CommonPool。
UI为主线程,UI线程,只有context是UI的launch或者async的block lambda中才能更新UI
CommonPool为公共的线程池,在context是CommonPool的lauch或者async中的block lambda中可以异步处理耗时操作。
launch(UI) {
text.setText("UI")
}
async(UI) {
text.setText("UI")
}
launch(CommonPool) {
delay(1000)
}
async(CommonPool) {
delay(1000)
}
4、async/Deferred
async{
loge(message = "outer start")
val inner = async{
loge(message = "inner start")
//do something
delay(1000)
loge(message = "inner stop")
"stop"
}
loge(message = "outer wait itself start")
delay(500)
loge(message = "outer wait itself stop")
loge(message = "outer wait inner")
val await = inner.await()
loge(message = "outer stop")
await
}
// 依次打印
// 16:30:41.759 14668-14737/com.moo.demogo E/DemoGo: outer start
// 16:30:41.761 14668-14737/com.moo.demogo E/DemoGo: outer wait itself start
// 16:30:41.768 14668-14737/com.moo.demogo E/DemoGo: inner start
// 16:30:42.268 14668-14738/com.moo.demogo E/DemoGo: outer wait itself stop
// 16:30:42.268 14668-14738/com.moo.demogo E/DemoGo: outer wait inner
// 16:30:42.771 14668-14738/com.moo.demogo E/DemoGo: inner stop
// 16:30:42.772 14668-14738/com.moo.demogo E/DemoGo: outer stop
从打印的信息可以看出outer(外层async)开始线性调用,打印outer start,在inner创建之后inner也开始执行,(outer wait itself start打印在inner start之前是因为inner async在创建的过程中会耗费极少的时间,而在这段时间内outer已经执行到下一步,理论上在inner创建之后,inner和outer之后都是同步执行)当outer等待500ms之后 outer打印outer wait itself stop同时开始等待inner,打印outer wait inner,下面这句代码val await = inner.await()
为Kotlin协程重点。正常情况下,outer会直接打印outer stop,之后等待500ms之后 inner stop。但是由于inner.await(),outer会挂起,等待inner执行结束,返回字符串“stop”之后,outer再结束,这也就是为什么最后是outer wait inner 500ms之后inner stop 然后才是outer stop
5、launch/Job
launch{
loge(message = "outer start")
val inner = launch{
loge(message = "inner start")
//do something
delay(1000)
loge(message = "inner stop")
}
loge(message = "outer wait itself start")
delay(500)
loge(message = "outer wait itself stop")
loge(message = "outer wait inner")
inner.join()
loge(message = "outer stop")
}
// 依次打印
// 16:57:05.431 20131-20298/com.moo.demogo E/DemoGo: outer start
// 16:57:05.432 20131-20298/com.moo.demogo E/DemoGo: outer wait itself start
// 16:57:05.432 20131-20300/com.moo.demogo E/DemoGo: inner start
// 16:57:05.940 20131-20298/com.moo.demogo E/DemoGo: outer wait itself stop
// 16:57:05.940 20131-20298/com.moo.demogo E/DemoGo: outer wait inner
// 16:57:06.439 20131-20298/com.moo.demogo E/DemoGo: inner stop
// 16:57:06.441 20131-20300/com.moo.demogo E/DemoGo: outer stop
打印信息和async/Deferred一致,区别在与lauch返回Job,挂起方法为job.join()且没有返回值。
async和launch可以根据是否需要返回值这一特点选择使用或者混合使用
launch {
loge(message = "outer start")
val inner = async {
loge(message = "inner start")
//do something
delay(1000)
loge(message = "inner stop")
"stop"
}
loge(message = "outer wait itself start")
delay(500)
loge(message = "outer wait itself stop")
loge(message = "outer wait inner")
val await = inner.await()
//deal result await
loge(message = "outer stop")
}