Androdi kotlin Coroutines(协程)详解 (一)
Androdi kotlin Coroutines(协程)详解 (二)
Androdi kotlin Coroutines(协程)详解 (三)
Androdi kotlin Coroutines(协程)详解 (四)
Androdi kotlin Coroutines(协程)详解 (五)
Androdi kotlin Coroutines(协程)详解 (六)
五、几个重要的函数
5.1 async函数
创建协程并返回结果 [Deferred<T>] 的实现.异步实现,可以返回耗时任务的执行结果, 多个 async 任务是并行的, async返回的是一个 Deferred<T> ,需要调用其 await() 方法获取结果。
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyDeferredCoroutine(newContext, block) else
DeferredCoroutine<T>(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
参考用法:
private fun asyncCoroutine() {
LogUtils.d("asyncCoroutine start ${Thread.currentThread().name}")
val result = GlobalScope.launch(Dispatchers.Main) {
val one = async {
delay(1000L) // 假设我们在这里做了一些有用的事
return@async 13
}
val two = async {
delay(1000L) // 假设我们在这里也做了一些有用的事
return@async 29
}
LogUtils.d("The answer is ${one.await() + two.await()}")
}
LogUtils.d("asyncCoroutine end ${Thread.currentThread().name}")
}
5.1.1 结构化并发
提取出一个函数并发的调用 doSomethingUsefulOne 与 doSomethingUsefulTwo 并且返回它们两个的结果之和。 由于 async 被定义为了 CoroutineScope 上的扩展,我们需要将它写在作用域内,并且这是 coroutineScope 函数所提供的:
suspend fun concurrentSum(): Int = coroutineScope {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
one.await() + two.await()
}
这种情况下,如果在 concurrentSum 函数内部发生了错误,并且它抛出了一个异常, 所有在作用域中启动的协程都会被取消。
fun main() = runBlocking<Unit> {
try {
failedConcurrentSum()
} catch(e: ArithmeticException) {
println("Computation failed with ArithmeticException")
}
}
suspend fun failedConcurrentSum(): Int = coroutineScope {
val one = async<Int> {
try {
delay(Long.MAX_VALUE) // 模拟一个长时间的运算
42
} finally {
println("First child was cancelled")
}
}
val two = async<Int> {
println("Second child throws an exception")
throw ArithmeticException()
}
one.await() + two.await()
}
请注意,如果其中一个子协程(即 two )失败,第一个 async 以及等待中的父协程都会被取消
5.2 withContext函数
有返回结果,一般来说,多个 withContext 任务是串行的
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return ...
}
示例如下:
CoroutineScope(Dispatchers.Main).launch {
val time1 = System.currentTimeMillis()
val task1 = withContext(Dispatchers.IO) {
delay(2000)
Log.e("TAG", "1.执行task1.... [当前线程为:${Thread.currentThread().name}]")
"one" //返回结果赋值给task1
}
val task2 = withContext(Dispatchers.IO) {
delay(1000)
Log.e("TAG", "2.执行task2.... [当前线程为:${Thread.currentThread().name}]")
"two" //返回结果赋值给task2
}
Log.e("TAG", "task1 = $task1 , task2 = $task2 , 耗时 ${System.currentTimeMillis()-time1} ms [当前线程为:${Thread.currentThread().name}]")
}
5.3 invoke函数
使用给定的[CoroutineDispatcher]调用指定的挂起块,挂起直到它完成,并返回结果。
5.4 launch
启动协程,挂起状态, lauch 是非阻塞的
5.5 delay函数
延时,可以看成Thread.sleep(),不过与sleep不同的是,delay函数是挂起状态,而sleep是阻塞的。