Keyword: coroutine
这几天在使用网路功能时,都使用到了Kotlin的Coroutine,在撰写KMM乃至於大部分的Kotlin移动端应用,都有Coroutine的身影.
这边的介绍是简略版的,主要是提到如何去使用,在KMM的专案中会不避免地遇到许多Coroutine的使用.真的要讲的话可以独立开一个铁人赛项目.
刚好我们团员这次有针对Coroutine进行铁人赛!内容非常详尽!如果想要了解更多,欢迎订阅
Coroutine 停看听 :: 2021 iThome 铁人赛
Coroutine是一个自创词,由代表共同的Co与工作常规的routine两个词合并起来,在wiki上面被翻作"共常",但是我更喜欢大陆普遍的说法,“协程”.描述了Coroutine让不同工作项共同运作的特色.
在Kotlin的Coroutine中,当某个函式正在等待某个事件发生的时候,可能是等待网路请求的结果,可能是等待使用者的回应或操作,甚至可能是印表机印速度太慢,导致Cpu无事可干.白白浪费掉这些效能,所以就有人想到,我们能不能让等待事件结果的函式,先把目前的状态储存起来,解放这些宝贵的资源,先给现在正需要资源的其他人,等到等待的事件发生了,再从暂存状态复原回来,继续执行.这就是Coroutine环境的特色
Kotlin的Coroutine,和一般常说Coroutine上有些许差别,由於Kotlin是跑在JVM上的,而严格来说,JVM没有提供真正的Coroutine环境,因此实际上还是用Thread去模拟Coroutine环境.在与其他语言的使用者交流时可能需要注意到这点.
另外,Kotlin正在开发其他语言的版本,如果在其他语言平台,且有支援Coroutine环境,那时就能真正使用到Coroutine,而不是JVM上以Thread模拟的Coroutine环境.
interface CafeApi {
suspend fun fetchCafeFromApi(city:String): List<CafeResponseItem>
}
这是前几天写在shared内的一个suspend 函式,suspend函式就有如上面介绍的一样,具有暂时交出控制权并且暂存目前状况的能力,因为这是一个Ktor的网路请求,所以需要等待发生的事件,就在发出网路请求後,一直到网路请求的回应.如果使用普通的Thread,在这段时间内Thread都是浪费的.所以把这个function标注为suspend,让Kotlin减少浪费的资源与效能.
我们在Android内部使用Coroutine的时候,就会像
class MainViewModel : ViewModel() {
...
fun fetchCafeData(city: String = "") {
viewModelScope.launch() {
val result = async { dataRepository.fetchCafesFromNetwork(city) }
cafeList.value = result.await()
}
}
...
}
我们外面使用了一个scope包裹了所有的suspend函式,由於suspend函式可以回复的特性,必须运行在一个coroutineScope中,不然需要回复状态时,suspend函式不知道自己该回到哪边.
而scope有许多种,画面层使用的lifecycleScope,ViewModel曾使用的viewModelScope,以及全局共用的globalScope等等.这次就是用跟ViewModel生命周期绑定的viewModelScope
由於这次是拉取网路资料,因此这个fetchCafesFromNetwork将会有回传值,我们使用async关键字将这个部分包裹起来,并且将回传的部分用一个result参数代表.
当我们要使用到其中的数据时,使用await()呼叫,这样在结果回来前,这段的coroutine都会被suspend,直到有结果回传.
写一块来验证看看
class MainViewModel : ViewModel() {
...
fun checkAsync() {
viewModelScope.launch() {
val result1 = async { delaySuspendFunction1() }
val result2 = async { delaySuspendFunction2() }
println("job1 : "+result1.await()+ " at" + System.currentTimeMillis())
println("job2 : "+result2.await()+ " at" + System.currentTimeMillis())
}
}
private suspend fun delaySuspendFunction1() {
withContext(Dispatchers.IO){
delay(1000L)
"result1 "
}
}
private suspend fun delaySuspendFunction2() {
withContext(Dispatchers.IO){
delay(10L)
"result2 "
}
}
...
}
可以看到在job1印出来後,几乎马上job2的文字就出现了,因为job2早就执行完了,在等待job1的await回传,可以把两行的顺序交换,看看有什麽结果.
今天先大概介绍到这边,明天会来讲Coroutine 的一些注意点
>>: D4 - 彭彭的课程#Python 简介、安装、与快速开始
Q4. PHP 反序列化利用? POP Chain 常见的涵数:exec()、passthru()、...
你是不是常常在编辑试算表时遇到”####”呢?别紧张,其实出现这个符号并不是你输入错误喔,而是你的栏...
在[Day 01]时就有提及,未来具有边缘智能(Edge AI)的智慧物联网(AIoT)装置一定少不...
Class Component用的是ES6中的class语法建立元件,接着去 extends(继承)...
belongs_to 的设定 optional 在 Rails 5.1 之後的版本,belongs_...