如何等待 Kotlin 协程完成

时间:2021-05-18 18:43:38

标签: android kotlin android-room kotlin-coroutines

我已经阅读了数十篇帖子,但不知何故,似乎没有一个答案对我有用。

我想要实现的是在Fragment中等待ViewModel使用Room进行操作。

道:

@Query("SELECT * FROM my_table WHERE id = :id")
suspend fun getMyData(id: Long): List<Item>

在 ViewModel 中,我不需要返回任何内容,只需使用数据库中的一些数据更新我的变量即可。我也在这里尝试了其他方法,即返回一个 Deferred

视图模型:

suspend fun updateData(myItem: Item) {
    for (myField in myItem.fields) {
        myField.someOtherField = myDao.getMyData(myField.id)
    }
}

我尝试过使用 runBlocking、lifecycleScope.launch 和 async.await() 等待,但总是得到相同的结果。我需要处理更新的项目。

片段:

runBlocking {
    val job = launch{
        viewModel.updateData(myItem)
    }
    job.join()
    doSomethingElseWithUpdatedmyItem(myItem) //this always executes before viewModel.updateData(myItem) even starts
}                            

2 个答案:

答案 0 :(得分:0)

如果不涉及其他代码,则应按此顺序运行。

runBlocking {
    println("run blocking")
    val job = launch {
        delay(1000)
        println("launch new job")
    }
    job.join()
    println("do something")
}

此代码将打印:

run blocking
launch new job
do something

在您的情况下,我会使用 withContext/async 作为 viewModel.updateData 逻辑。

答案 1 :(得分:0)

是否有理由不只是在协程中运行最终代码

lifecycleScope.launch {
    viewModel.updateData(myItem)
    doSomethingElseWithUpdatedmyItem(myItem)
}   

这就是使用协程的真正用途。

不过,最终,我想知道这里的问题是否与您的项目的可变性有关。为什么不返回一组新的项目而不是尝试改变现有的项目?然后你会有类似的东西

suspend fun updateData(myItem: Item): Item {
    return myItem.copy(
        fields = myItem.fields.map { field -> myDao.getMyData(field.id) }
    )
}

然后您将更新后的项目传递给您的最终函数:

lifecycleScope.launch {
    val updatedItem = viewModel.updateData(myItem)
    doSomethingElseWithUpdatedmyItem(updatedItem)
}