有些 APIs 是需要长时间运行,并且需要调用者阻塞直到这些调用完成(比如网络 IO ,文件 IO ,CPU 或者 GPU 比较集中的工作)。协程提供了一种避免线程阻塞并且用一种更轻量级,更易操控到操作:协程暂停。
添加Kotlin协程依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"
当一个函数被 suspend
修饰时表示可以被挂起,调用它会导致挂起协程,挂起函数可以和正常函数那样接受参数返回结果,但只能在协程中调用或着被其他挂起函数调用。
suspend fun doSomething(){
//do something
delay(1000)
}
因为delay为Kotlin封装的挂起函数,所以调用delay的函数也必须是挂起函数。
在已有的Api中,Kotlin提供了两种方式实现协程 async/Deferred和launch/Job
public actual fun async(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> T
): Deferred {
val newContext = newCoroutineContext(context, parent)
val coroutine = if (start.isLazy)
LazyDeferredCoroutine(newContext, block) else
DeferredCoroutine(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()
}
两个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)
}
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
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()且没有返回值。
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")
}