是协程不是携程
看看协程(Coroutine)!
Section titled “看看协程(Coroutine)!”至少在做某些耗时操作的时候(比如网络请求和文件读写)要用到它
一般来说协程比线程好使,协程里可以用delay挂起,和线程的sleep挺不同
kt里边能开协程的方式挺多
比如
GlobalScope.launch { println("codes run in coroutine scope") delay(1500) println("Ciallo~(∠·ω< )⌒★")}delay只会挂起这个协程,不像sleep会祸及自身与包含的协程
再如
runBlocking { launch { println("launch1") delay(1000) println("launch1 finished") } launch { println("launch2") delay(1000) println("launch2 finished") }}runBlocking如果不跑完,那父线程也不会结束
在协程里边可以用很多个launch来开很多个协程
当然如果不是像runBlocking这种东西外边的线程(协程)结束了那里边的协程也会结束
在函数前面加个suspend就是挂起(暂停)函数,挂起函数里面也可以用delay来咋瓦鲁多
比如
suspend fun printDot() { println(".") delay(1000) println(".")}但是如果不在协程里面是不能delay的,所以可以让它继承自coroutineScope这个会创建一个协程的函数,变成这样(coroutineScope像runBlocking一样自己不结束上一级也不结束)
suspend fun printDot() = coroutineScope { println(".") delay(1000) println(".")}然后这玩意放哪都能生效了
对于大多数启动协程的方法而言,这个参数不是必须的,只有withContext()强制需要
添加这个参数就能添加这个参数(废话
CoroutineScope(Dispatchers.IO)让协程在IO线程池中进行
CoroutineScope(Dispatchers.Main)可以在主线程执行UI相关操作(这是Android独享)
CoroutineScope(Dispatchers.Default)则是一种默认的低并发的策略
创建协程的常用方法
Section titled “创建协程的常用方法”GlobalScope会创建一个与应用同寿的协程,实际中这样用会出现警告波浪线
lifecycleScope会创建一个与现有Activity或Fragment同寿的协程
viewModelScope则是创建和ViewModel同寿的协程
CoroutineScope可以创建自定义的作用域
CoroutineScope
Section titled “CoroutineScope”事实上上面的launch会返回一个Job对象,用来管理这个协程的一些关系,也可以拿来取消这个协程,比如
val job = GlobalScope.launch { // 我不是代码}job.cancel()然后就会有人发现:每个协程都要一个Job的话,那协程一多起来不得麻烦死
于是为了解决这种神奇的麻烦问题,可以像下面这样用Job
val job = Job()val scope1 = CoroutineScope(job) // 在job的作用域里val scope2 = CoroutineScope(job) // 也在job的作用域里scope1.launch { // 我也不是代码}scope2.launch { // 我说我是代码你信吗}job.cancel() // 全部取消这样可就方便多了,而且如果你想的话,还可以这样写
val myScope = CoroutineScope(Job() + Dispatchers.Default)async?好眼熟的东西
Section titled “async?好眼熟的东西”和launch一样,async也可以拿来启动一个协程,但只能在协程里面启动
这async最大的特色就是可以搭配await()来获得其启动的协程的返回值,由于要获得返回值,所以await一定要等对应的协程跑完才会让你继续跑
下面就是书上的某个例子
runBlocking { val start = System.currentTimeMillis() val result1 = async { delay(1000) 5 + 5 }.await() val result2 = async { delay(1000) 4 + 6 }.await() println("result is ${result1 + result2}.") val end = System.currentTimeMillis() println("cost ${end - start} ms.")}最终的运行结果是超过2000ms的,因为每个await()都会等一秒钟
改成这样就一共只要一秒钟了:
runBlocking { val start = System.currentTimeMillis() val result1 = async { delay(1000) 5 + 5 } val result2 = async { delay(1000) 4 + 6 } println("result is ${deferred1.await() + deferred2.await()}.") val end = System.currentTimeMillis() println("cost ${end - start} ms.")}显然都在print那里await()了,真是省时省事
withContext()
Section titled “withContext()”这玩意在效果上就是async的简化版
runBlocking { val result = withContext(Dispatchers.Default) { 5 + 5 } println(result)}相当于
runBlocking { val result = async{ 5 + 5 }.await() println(result)}如此而已