Android Kotlin 协程async

Android Kotlin 协程async Android Kotlin 协程asyncmeasureTimeMillis 统计一段代码耗时内敛函数 measureTimeMillis{ } 可以很方便的统计一段代码执行的耗时。使用GlobalScope.launch { val time measureTimeMillis { delay(1000) Log.d(zyj-, 日志) } Log.d(zyj-, 耗时:$time) }输出结果D/zyj-: 日志 D/zyj-: 耗时:1010使用默认顺序定义两个耗时函数suspend fun doSomethingUsefulOne(): Int { delay(1000L) // 假设我们在这里做了一些有用的事 return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // 假设我们在这里也做了一些有用的事 return 29 }使用默认的顺序调用val time measureTimeMillis { val one doSomethingUsefulOne() val two doSomethingUsefulTwo() println(The answer is ${one two}) } println(Completed in $time ms)它的打印输出如下The answer is 42 Completed in 2017 ms从输出结果上看两个耗时任务是串行的总耗时 耗时函数1 耗时函数2使用 async 并发如果 doSomethingUsefulOne 与 doSomethingUsefulTwo 之间没有依赖并且我们想更快的得到结果让它们进行 并发 吗这就是async 可以帮助我们的地方。在概念上async 就类似于 launch。它启动了一个单独的协程与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值而 async 返回一个 Deferred—— 一个非阻塞 future 这代表了一个将会在稍后提供结果的 promise。你可以使用 .await()在一个延期的值上得到它的最终结果 但是 Deferred 也是一个 Job所以如果需要的话你可以取消它。val time measureTimeMillis { val one async { doSomethingUsefulOne() } val two async { doSomethingUsefulTwo() } println(The answer is ${one.await() two.await()}) } println(Completed in $time ms)它的打印输出如下The answer is 42 Completed in 1017 ms这里快了两倍因为两个协程并发执行。 请注意使用协程进行并发总是显式的。惰性启动的 async可选的async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。 在这个模式下只有结果通过 await 获取的时候协程才会启动或者在 Job 的 start函数调用的时候。运行下面的示例val time measureTimeMillis { val one async(start CoroutineStart.LAZY) { doSomethingUsefulOne() } val two async(start CoroutineStart.LAZY) { doSomethingUsefulTwo() } // 执行一些计算 one.start() // 启动第一个 two.start() // 启动第二个 println(The answer is ${one.await() two.await()}) } println(Completed in $time ms)它的打印输出如下The answer is 42 Completed in 1017 ms因此在先前的例子中这里定义的两个协程没有执行但是控制权在于程序员准确的在开始执行时调用 start。我们首先 调用 one然后调用 two接下来等待这个协程执行完毕。注意如果我们只是在 println 中调用 await而没有在单独的协程中调用 start这将会导致顺序行为直到 await 启动该协程 执行并等待至它结束这并不是惰性的预期用例。 在计算一个值涉及挂起函数时这个 async(start CoroutineStart.LAZY)的用例用于替代标准库中的 lazy 函数。构建async 风格的函数我们可以定义异步风格的函数来 异步 的调用 doSomethingUsefulOne 和 doSomethingUsefulTwo 并使用 async 协程建造器并带有一个显式的 GlobalScope 引用。 我们给这样的函数的名称中加上“……Async”后缀来突出表明事实上它们只做异步计算并且需要使用延期的值来获得结果。// somethingUsefulOneAsync 函数的返回值类型是 DeferredInt fun somethingUsefulOneAsync() GlobalScope.async { doSomethingUsefulOne() } // somethingUsefulTwoAsync 函数的返回值类型是 DeferredInt fun somethingUsefulTwoAsync() GlobalScope.async { doSomethingUsefulTwo() }使用class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 我们可以在协程外面启动异步执行 val one somethingUsefulOneAsync() val two somethingUsefulTwoAsync() // 但是等待结果必须调用其它的挂起或者阻塞 // 当我们等待结果的时候这里我们使用 GlobalScope.launch{ } 来阻塞主线程 GlobalScope.launch { println(The- answer is ${one.await()} ${two.await()}) } } }这种带有异步函数的编程风格仅供参考因为这在其它编程语言中是一种受欢迎的风格。在 Kotlin 的协程中使用这种风格是强烈不推荐的 原因如下所述。考虑一下如果 val one somethingUsefulOneAsync() 这一行和 one.await() 表达式这里在代码中有逻辑错误 并且程序抛出了异常以及程序在操作的过程中中止将会发生什么。 通常情况下一个全局的异常处理者会捕获这个异常将异常打印成日记并报告给开发者但是反之该程序将会继续执行其它操作。但是这里我们的 somethingUsefulOneAsync仍然在后台执行 尽管如此启动它的那次操作也会被终止。这个程序将不会进行结构化并发如下一小节所示。使用 async 的结构化并发让我们使用使用 async 的并发这一小节的例子并且提取出一个函数并发的调用 doSomethingUsefulOne 与 doSomethingUsefulTwo 并且返回它们两个的结果之和。 由于 async 被定义为了 CoroutineScope上的扩展我们需要将它写在作用域内并且这是 coroutineScope 函数所提供的suspend fun concurrentSum(): Int coroutineScope { val one async { doSomethingUsefulOne() } val two async { doSomethingUsefulTwo() } one.await() two.await() }这种情况下如果在 concurrentSum 函数内部发生了错误并且它抛出了一个异常 所有在作用域中启动的协程都会被取消。val time measureTimeMillis { println(The answer is ${concurrentSum()}) } println(Completed in $time ms)从上面的 main 函数的输出可以看出我们仍然可以同时执行这两个操作The answer is 42 Completed in 1017 ms取消始终通过协程的层次结构来进行传递import kotlinx.coroutines.* fun main() runBlockingUnit { try { failedConcurrentSum() } catch(e: ArithmeticException) { println(Computation failed with ArithmeticException) } } suspend fun failedConcurrentSum(): Int coroutineScope { val one asyncInt { try { delay(Long.MAX_VALUE) // 模拟一个长时间的运算 42 } finally { println(First child was cancelled) } } val two asyncInt { println(Second child throws an exception) throw ArithmeticException() } one.await() two.await() }请注意如果其中一个子协程即 two失败第一个 async 以及等待中的父协程都会被取消Second child throws an exception First child was cancelled Computation failed with ArithmeticException后文Android Kotlin 更多学习资料可以扫码免费领取《史上最详Android版kotlin协程入门进阶实战》第一章 Kotlin协程的基础介绍​ ● 协程是什么​ ● 什么是Job 、Deferred 、协程作用域​ ● Kotlin协程的基础用法第二章 kotlin协程的关键知识点初步讲解​ ● 协程调度器​ ● 协程上下文​ ● 协程启动模式​ ● 协程作用域​ ● 挂起函数第三章 kotlin协程的异常处理​ ● 协程异常的产生流程​ ● 协程的异常处理第四章 kotlin协程在Android中的基础应用​ ● Android使用kotlin协程​ ● 在Activity与Framgent中使用协程​ ● ViewModel中使用协程​ ● 其他环境下使用协程第五章 kotlin协程的网络请求封装​ ● 协程的常用环境​ ● 协程在网络请求下的封装及使用​ ● 高阶函数方式​ ● 多状态函数返回值方式第六章 深入kotlin协程原理一​ ● suspend的花花肠子​ ● 藏在身后的-Continuation​ ● 村里的希望-SuspendLambda第七章 深入kotlin协程原理二​ ● 协程的那些小秘密​ ● 协程的创建过程​ ● 协程的挂起与恢复​ ● 协程的执行与状态机第八章 Kotlin Jetpack 实战​ ● 从一个膜拜大神的 Demo 开始​ ● Kotlin 写 Gradle 脚本是一种什么体验​ ● Kotlin 编程的三重境界​ ● Kotlin 高阶函数​ ● Kotlin 泛型​ ● Kotlin 扩展​ ● Kotlin 委托​ ● 协程“不为人知”的调试技巧​ ● 图解协程原理第九章 Kotlin 协程 Retrofit MVVM优雅的实现网络请求​ ● 项目配置​ ● 实现思路​ ● 协程实现​ ● 协程 ViewModel LiveData实现​ ● 后续优化​ ● 异常处理​ ● 更新Retrofit 2.6.0由于文章内容比较多篇幅有限资料已经被整理成了PDF文档有需要 Android中高级面试必知必会 完整文档的可以加微信可免费领取!承诺100%免费更有更多资料加微信免费领取