如何等待 Kotlin 协程完成

3

我已经阅读了许多帖子,但是在我的情况下似乎没有一个答案有效。

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

Dao:

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

在ViewModel中,我不需要返回任何东西,只需使用从数据库中获取的一些数据更新我的变量。我在这里尝试了其他方法,例如返回Deferred。
ViewModel:
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
}                            

你的代码应该可以正常工作。是否还涉及其他代码? - Louis Wasserman
@LouisWasserman,我没有看到任何相关的内容。唯一能想到的是,runBlocking块位于观察者内部,并且myItem实际上是从该观察者返回的值。这可能会有一些影响吗? - suue
你到底是用什么来证明 doSomethingElseWithUpdatedmyItemviewModel.updateData(myItem) 之前执行的? - Brian Yencho
2个回答

1
如果没有其他代码参与,那么它应该按照这个顺序运行。
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

你为什么不在协程中直接运行最终代码呢?

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)
}   

或者只需用runBlocking替换lifecycleScope.launch,这是相同的思路:

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

由于某些原因,这并不能保证挂起函数执行的顺序。 - IgorGanapolsky
1
我不确定你的意思……你是在谈论updateDatadoSomethingElseWithUpdatedmyItem的顺序吗?它们必须按照它们在那里编写的顺序运行。它们在同一个协程中运行。这与原始帖子不同,原始帖子中有一个嵌套的launch调用。 - Brian Yencho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接