Kotlin - 如何等待异步协程完成工作

Kotlin - How to wait for async coroutine to complete the job

我有两个功能。第一个函数用于检查 ID 在数据库中是否可用,然后它将 return 基于结果的布尔值。如果 Id 存在于数据库中,则第二个函数取决于第一个函数响应,然后显示弹出消息,否则将数据插入数据库。

这是我的问题:

如果 ID 仍然存在于数据库中,最初 checkIfIDExistsInDatabase() return false 那么它将进入 else 条件,同时它将完成异步协程的工作,所以我如何告诉协程等待完成工作然后进入其他条件?

-> 如果 ID 存在于数据库中: { 实际结果:显示弹出消息以及在数据库中插入 ID 也

预期结果:应该只显示弹出消息 }

-> 如果数据库中不存在 ID: { 它按预期工作 }

private fun checkIfIDExistsInDatabase(): Boolean {
        var isIDExists = false
        GlobalScope.launch {
            val isIDAvailable = GlobalScope.async { withContext(Dispatchers.IO) { bbdViewModel.isIDExists(id) } }
            if (isIDAvailable.await()) {
                Handler(Looper.getMainLooper()).post {
                    isIDExists = true
                    Dialog.getInstance(activity)
                            .setMessage(R.string.id_already_exists_in_db)
                            .setPositiveButton(R.string.ok, null)
                            .show()
                }
            }
        }
        return isIDExists
    }


private fun findId() {
            if (checkIfIDExistsInDatabase) {
                //want to show pop that ID is already inserted into DB
            } else {
                //want to insert ID in DB
            }
        }

注意:如果我使用 runBlocking 而不是 GlobalScope。async/launch 那么它工作正常,但不推荐使用 runBlocking。

我已经完成了几个 SO 答案(许多答案与使用 runBlobking() 相关)但没有为我的查询找到解决方案。请给我一些建议。我能做什么?

当您使用 GlobalScope.launch 时,它会构建一个协同程序并安排它执行,在执行完这条语句后,底层线程将移动到下一条语句。让我们看看 checkIfIDExistsInDatabase 语句的执行顺序

private fun checkIfIDExistsInDatabase(): Boolean {
    var isIDExists = false    // Executed first
    GlobalScope.launch {      // Executed second

    // Any code inside launch is Executed fourth

    }
    return isIDExists        // Executed third
}

这意味着 checkIfIDExistsInDatabase 将始终 return false,因为协程尚未开始执行。

您的问题的一个解决方案是使用 suspend 函数,如果您使用的是 Room 数据库,那么您可以使用 suspend 修饰符标记您的 dao 函数。这将使您能够以更好的方式编写代码,而无需所有协程作业状态管理。

这可以通过以下步骤完成

  1. suspend 修饰符标记 isIDExists 函数

  2. 现在更新您的 activity 进行以下更改

// Declare LiveData object
private val showPopUp: MutableLiveData<Boolean> = MutableLiveData()

// Launch the coroutine using lifecycleScope, don't use GlobalScope
private fun checkIfIDExistsInDatabase() = lifecycleScope.launch {
    if(bbdViewModel.isIDExists(id)){
        showPopUp.postValue(true)
    }
    else{
        // Insert the id in DB
    }
}


// Observe the LiveData object in Activity onCreate to show the popup
showPopUp.observe(this, Observer{
    // Show the popup dialog here
})