如何使用 Kotlin 协程执行顺序后台任务
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'
- 1
- 2
然后同步你的项目,让我们开始吧。
2. 创建一个CoroutineScope 实例。
这将定义协程将在其中运行的上下文。
val myScope = CoroutineScope(Dispatchers.IO)
- 1
3.创建一些后台任务作为挂起函数
suspend fun doTask1() { repeat(5) { i -> Log.d("CoroutinesTasks", "doTask1: $i") } }
<span class="token keyword">suspend</span> <span class="token keyword">fun</span> <span class="token function">doTask2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> i <span class="token operator">-></span> Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"CoroutinesTasks"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"doTask2: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">$</span><span class="token expression">i</span></span><span class="token string">"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">suspend</span> <span class="token keyword">fun</span> <span class="token function">doTask3</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> i <span class="token operator">-></span> Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"CoroutinesTasks"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"doTask3: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">$</span><span class="token expression">i</span></span><span class="token string">"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
现在我们已经创建了三个挂起函数,每个函数将打印一条日志 5 次,这是对后台任务的简单模拟,例如使用 Room 或 Retrofit 制作任务。
4. 使用异步和等待
要按顺序运行这些任务,您可以使用async
和await
函数。async
创建一个新的 Coroutine 并返回一个Deferred对象,而await等待 Coroutine 的结果并返回它的值。
val myScope = CoroutineScope(Dispatchers.IO)
myScope.launch {
Log.d("CoroutinesTasks", "onCreate: Started")
在此示例中,我们使用async按顺序运行每个任务,并使用await等待其结果。这确保了每个任务都按照我们想要的顺序执行,而不会阻塞主线程。
现在,如果你运行这个应用程序,你会看到这样的结果:
- 开始执行第一个任务,直到第一个任务完成后才执行第二个任务。
- 第一个任务完成,其结果存储在 result1 变量中。
- 开始执行第二个任务,直到第二个任务完成后才开始执行第三个任务。
- 第二个任务完成,它的结果存储在 result2 变量中。
- 开始执行第三个任务,直到第三个任务完成后才开始执行它之后的任何事情。
- 第三个任务完成,结果保存在result3变量中。
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")
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)
}
}