赞
踩
- public interface CoroutineScope {
- public val coroutineContext: CoroutineContext
- }
- public fun CoroutineScope.launch(
- context: CoroutineContext = EmptyCoroutineContext,
- start: CoroutineStart = CoroutineStart.DEFAULT,
- block: suspend CoroutineScope.() -> Unit
- ): Job {
- ...省略
- }
- private fun request() {
- lifecycleScope.launch {
- coroutineScope { // 协同作用域,抛出未捕获异常时会取消父协程
- launch { }
- }
- supervisorScope { // 主从作用域,抛出未捕获异常时不会取消父协程
- launch { }
- }
- }
- }
注意这两个函数的作用只是定义了2个作用域而已,如果想要启动新的子协程请在里面调用launch。如果需要异步请使用async。
还可以进行一些简单的封装,比如我们可以定义一个 suspend 方法,内部返回一个 coroutineScope 作用域对象来执行一个传入的协程代码块:
- private suspend fun saveLocal(coroutineBlock: (suspend CoroutineScope.() -> String)? = null): String? {
- return coroutineScope {
- // 以下几种写法等价,都是执行block代码块
- // coroutineBlock!!.invoke(this)
- // coroutineBlock?.invoke(this)
- // if (coroutineBlock != null) {
- // coroutineBlock.invoke(this)
- // }
- coroutineBlock?.let { block ->
- block()
- }
- }
- }
- MainScope().launch {
- println("执行在一个协程中...")
- val result = saveLocal {
- async(Dispatchers.IO) {
- "123456"
- }.await()
- }
- println("一个协程执行完毕... result:$result")
- }
例如,假设我们定义一个用于异步获取两个文档的 coroutineScope。通过对每个延迟引用调用 await(),我们可以保证这两项 async 操作在返回值之前完成:
- suspend fun fetchTwoDocs() = coroutineScope {
- val deferredOne = async { fetchDoc(1) }
- val deferredTwo = async { fetchDoc(2) }
- deferredOne.await()
- deferredTwo.await()
- }
假如像上面这样直接使用coroutineScope,那么async执行完成,coroutineScope中排在async之后的代码有可能被调度到某个子线程中执行,即上面的红色部分执行完后,蓝色部分可能运行在某个子线程中。如下图:
所以在Android中,最好是在lifecycleScope或viewModelScope中去使用async, 这样能保证async之后的代码仍然执行在主线程上。但是此时在lifecycleScope或viewModelScope中调用的async中的代码也会执行在主线程(虽然是异步的,但既然是主线程就会有IO太长阻塞主线程的风险),也就是说async默认跟父协程的调度器是一样的,因此,如果有需要,此时可以为async指定线程调度器。如下:
除了单独调用每个await方法,还可以对集合使用 awaitAll(),如以下示例所示:
- suspend fun fetchTwoDocs() = // called on any Dispatcher (any thread, possibly Main)
- coroutineScope {
- val deferreds = listOf( // fetch two docs at the same time
- async { fetchDoc(1) }, // async returns a result for the first doc
- async { fetchDoc(2) } // async returns a result for the second doc
- )
- deferreds.awaitAll() // use awaitAll to wait for both network requests
- }
虽然 fetchTwoDocs() 使用 async 启动新协程,但该函数使用 awaitAll() 等待启动的协程完成后才会返回结果。 此外,coroutineScope 会捕获协程抛出的所有异常,并将其传送回调用方。
写法上需要注意的点:
- suspend fun main() = runBlocking {
- val times = measureTimeMillis {
- // 这样写是串行执行,总耗时2s
- val one = doOne()
- val two = doTwo()
- println("The result is ${one + two}")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。