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
函数。这将使您能够以更好的方式编写代码,而无需所有协程作业状态管理。
这可以通过以下步骤完成
用 suspend
修饰符标记 isIDExists 函数
现在更新您的 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
})
我有两个功能。第一个函数用于检查 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
函数。这将使您能够以更好的方式编写代码,而无需所有协程作业状态管理。
这可以通过以下步骤完成
用
suspend
修饰符标记 isIDExists 函数现在更新您的 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
})