在上一篇文章中,我们知道如果我们要以非同步的方式来执行,可以使用 Thread + callback 来写,不过使用 Callback 可能会发生两个问题,一是 callback hell;另一则是控制权转移 (Inversion of Control),让程序码变得不容易维护。
本篇文章,就让我们尝试使用 Coroutine 来改写吧。
要在专案里面使用 Coroutine ,必须先加上 dependency,如下:
dependencies{
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt")
}
如果是 Android 的话,需要使用下方的 dependency,因为 Coroutine 与 Android 的 Jetpack 有整合,所以使用下方的 dependency
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2")
}
前面我们定义了三个函式如下:
fun login(userName: String, password: String): Token { ... }
fun fetchLatestContent(token: Token): List<Contents> { ... }
fun showContents(contents: List<Contents>){ ... }
fun showContents() {
val token = login(userName, password)
val contents = fetchLatestContents(token)
showContents(contents)
}
suspend fun login(userName: String, password: String): Token { ... }
suspend fun fetchLatestContentAsync(token: Token): List<Contents> { ... }
showContents()
改成 Coroutine 的写法suspend fun showContents() = coroutineScope {
launch {
val token = login(userName, password)
val content = fetch(token)
withContext(Dispatchers.Main) {
showContents(content)
}
}
}
到这边我们就用 Coroutine 完成了一个非同步的程序,是不是很容易呢?看起来是不是很像是同步的程序码呢?
回头看一下我们做了哪些改动:
suspend
。showContents()
使用 coroutineScope
将程序码包起来。login()
以及 fetch()
在 launch{}
中执行。withContext(Dispatchers.Main)
将 showContents(content)
包起来。suspend
Kotlin 的 Coroutine 用 suspend
这个关键字来宣告该函式为可暂停的函式。
showContents()
使用 coroutineScope
将程序码包起来。前面我们定义了 suspend function
,这些可暂停的函式只能在 Coroutine 中使用,而 coroutineScope
是用来建立一个新的范围 (Scope),在 {}
内部的程序码,就是称为在 Coroutine 里面的程序。
login()
以及 fetch()
在 launch{}
中执行。launch{}
的功能类似 coroutineScope
,它也是用来定义一个 Coroutine 的范围,不过与 coroutineScope
不同的是,它会新建 coroutine ,而且它有一个回传值 Job
。
withContext(Dispatchers.Main)
将 showContents(content)
包起来我们可以把 coroutine 想成是执行绪(thread)的概念,利用背景的执行绪来执行耗时动作,完成之後,在由主执行绪来绘制画面。
前方的 launch{}
可以看作是建立一个新的执行绪,到了 withContext(Dispatchers.Main)
把 context 切回 Dispatchers.Main
也就是主执行绪,在主执行绪上进行画面的更新。
到这边我们已经完成了一个简单的 Coroutine 程序。我们注意到,使用 Coroutine,我们就不需要在非同步函式完成之後使用 Callback 将结果传出来。不知道你有没有发现,用 Coroutine 完成的程序码可以让非同步程序码以同步的程序码来撰写。
另外,我们可以轻松的切换执行绪,利用不同的 Coroutine scope 来做不同的事,如上方的程序码,我们使用 launch
让 login()
、 fetch()
让它们在背景运算,并且在执行完毕之後,我们使用 withContext(Dispatchers.Main)
将执行绪切回主执行绪,并在主执行绪上更新画面。
Kotlin Taiwan User Group
Kotlin 读书会
>>: < 关於 React: 开始打地基| useState()>
第一次压线发文耶,今天真的有点忙,到现在才发文。Menu就是功能表的表单,通常都会在介面的最上面,是...
身为前端开发者,整日与 JavaScript 这门程序语言打交道,应该都知道它是一个 single...
建立资料仓库是一个解决企业资料问题应用的过程,是企业资讯化发展到一定阶段必不可少的一步,也是发展资料...
Set与Map不同再於Set没有key,是指有包含值的特殊集合,且每个值只能出现一次不能重复。 Se...
前言 接下来我们要聊一个非常非常重要的东西,也就是关於错误的处理,而这个处理又称之为例外处理。 例外...