Kotlin 协程,谁不知道协程!因此,在这篇文章中,我们会讲到其中一个重要的部分,就是制作顺序后台任务。
大家好,我是 Abanoub,在这篇文章中,我将向您展示如何使用async和await以及使用withContext 的另一种方法使用协程来执行顺序后台任务。
顺序意味着如果你有3个任务,第一个任务将运行,第二个任务将在第一个任务完成后执行,第三个任务将在第二个任务完成后执行,依此类推。
1. 添加协程依赖
您需要将 kotlin 协程依赖项添加到您的build.gradle应用程序模块:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
然后同步你的项目,让我们开始吧。
2. 创建一个CoroutineScope 实例。
这将定义协程将在其中运行的上下文。
val myScope = CoroutineScope(Dispatchers.IO)
3.创建一些后台任务作为挂起函数
suspend fun doTask1() {
repeat(5) { i ->
Log.d("CoroutinesTasks", "doTask1: $i")
}
}
suspend fun doTask2() {
repeat(5) { i ->
Log.d("CoroutinesTasks", "doTask2: $i")
}
}
suspend fun doTask3() {
repeat(5) { i ->
Log.d("CoroutinesTasks", "doTask3: $i")
}
}
现在我们已经创建了三个挂起函数,每个函数将打印一条日志 5 次,这是对后台任务的简单模拟,例如使用 Room 或 Retrofit 制作任务。
4. 使用异步和等待
要按顺序运行这些任务,您可以使用async
和await
函数。async
创建一个新的 Coroutine 并返回一个Deferred对象,而await等待 Coroutine 的结果并返回它的值。
val myScope = CoroutineScope(Dispatchers.IO)
myScope.launch {
Log.d("CoroutinesTasks", "onCreate: Started")
val result1 = async { doTask1() }.await()
val result2 = async { doTask2() }.await()
val result3 = async { doTask3() }.await()
Log.d("CoroutinesTasks", "onCreate: Ended")
}
在此示例中,我们使用async按顺序运行每个任务,并使用await等待其结果。这确保了每个任务都按照我们想要的顺序执行,而不会阻塞主线程。
现在,如果你运行这个应用程序,你会看到这样的结果:
D onCreate: Started
D doTask1: 0
D doTask1: 1
D doTask1: 2
D doTask1: 3
D doTask1: 4
D doTask2: 0
D doTask2: 1
D doTask2: 2
D doTask2: 3
D doTask2: 4
D doTask3: 0
D doTask3: 1
D doTask3: 2
D doTask3: 3
D doTask3: 4
D onCreate: Ended
那么,什么是result1、result2、result3呢?
这些是结果,假设你在第一个任务中从 api 中获得了一个数据列表,那么 result1 将是这个列表,但是 suspend 函数返回类型应该是你想要作为结果获取它的数据,并且在第二个任务中,你会将这个列表保存到数据库中,然后你将它正常传递给第二个任务,我们将在一个例子中解释这一点。
5. 使用withContext()
您也可以使用withContext函数获得相同的结果。
val myScope = CoroutineScope(Dispatchers.IO)
myScope.launch {
Log.d("CoroutinesTasks", "onCreate: Started")
val result1 = withContext(Dispatchers.IO) {
doTask1()
}
val result2 = withContext(Dispatchers.IO) {
doTask2()
}
val result3 = withContext(Dispatchers.IO) {
doTask3()
}
Log.d("CoroutinesTasks", "onCreate: Ended")
}
例子:
将顺序后台任务定义为单独的挂起函数。例如,如果你想执行一个网络请求,然后是数据库访问,你可以定义两个单独的挂起函数:
suspend fun fetchPosts(): List<Post> {
// Perform network request
return myApi.getPosts()
}
suspend fun savePosts(posts: List<Post>) {
// Save data to database
myDao.savePosts(posts)
}
在 withContext
块中一个接一个地调用顺序后台任务。这将确保每个任务按顺序运行并且不会阻塞 UI 线程。例如:
myScope.launch {
val posts = withContext(Dispatchers.IO) {
fetchPosts()
}
withContext(Dispatchers.IO) {
savePosts(posts)
}
}
本例首先调用fetchPosts
进行网络请求,结果保存到posts变量中。然后,使用posts变量作为输入调用savePosts
以将帖子保存到数据库中。这两个任务在同一个协程范围内顺序运行。