作用域
协程的结构,首个要了解的就是作用域。
val scope = CoroutineScope(Dispatchers.IO) // 创建一个作用域 fun kotlinCoroutines(){ scope.launch { // {} 内代码执行区域(又叫协程体) // do something } }作用域一如字面意思就是可以生效的范围,为了解决以往启动一个Activity中的子线程后进行耗时操作后,即使页面已经被销毁了依然执行导致执行完毕后的回调后报错的问题。这个作用域可谓至关重要。
现在只要在页面onDestroy时调用scope.cancel()就可以中断代码的执行了。作用域的功能:生命周期管理。
override fun onDestroy() { super.onDestroy() scope.cancel() }Android平台 提供了几种常用的提前给好的作用域:
- lifecycleScope:绑定 Activity/Fragment 的生命周期,会在 Lifecycle 销毁时自动取消。
- viewModelScope:绑定 ViewModel 的生命周期,会在 ViewModel 销毁时自动取消。
其中 val scope = CoroutineScope(Dispatchers.IO) 中的 Dispatchers常用的有以下几种:
Dispatchers.Main | Android 主线程,用于更新 UI |
Dispatchers.IO | 网络请求、文件读写等 IO 密集型任务 |
Dispatchers.Default | 数据计算、排序等 CPU 密集型任务。默认线程数等于 CPU 核心数 |
挂起函数(suspend)
简单来说 withContext(Dispatchers.Main){} 就可以切换调度器(Dispatchers)
结合起来使用举例如下:
val scope = CoroutineScope(Dispatchers.IO) fun kotlinCoroutines(){ scope.launch { // 网络请求、数据操作等耗时操作 makeLoginRequest() // 切换到主线程 withContext(Dispatchers.Main){ updateUI() // 更新UI } } }挂起函数执行完毕后才能继续执行下面的代码。以上scope.lacunch{}协程体中的代码是顺序执行的! 点进withContent函数内部是加了suspend。
其中await() 和awaitAll()很好用
以前也有遇到情况就是几个接口要同时请求完毕才能结束,很丑陋,对吧?
var A = false var B = false var C = false ARequestNetWork(){ ... A = ture if( A && B && C ) {next()} } BRequestNetWork(){ ... B = ture if( A && B && C ) {next()} } CRequestNetWork(){ ... C = ture if( A && B && C ) {next()} }可以改成这样,当然,saync中的函数的ARequestNetWork()也都要改造成适配协程的,你直接在启动一个子线程协程还是无法感知的。
coroutineScope { val deferredA = async { ARequestNetWork() } val deferredB = async { BRequestNetWork() } val deferredC = async { CRequestNetWork() } deferredA.await() deferredB.await() deferredC.await() next() }这样写使用 awaitAll 更加简洁
coroutineScope { awaitAll{ async { ARequestNetWork() } async { BRequestNetWork() } async { CRequestNetWork() } } next() }