android - kotlin 中的多个异步等待
问题描述
obj in promoType = [list of string] 它更像是 10 个 firebase 查询在这里运行,查看 10 个特定的节点集并进一步下降。
我不确定,我是否需要在每个查询上都设置 async / await,但我想要的是运行 10 个这些查询,然后导致我的 couponKey 是否为空。我要做的就是显示输入的优惠券是否正确。
此外,在changeUserType(couponKey, couponFoundAtKey) 中,发生了一些数据库写入操作。
fun checkPromo(promoCodeET: String) = async(UI) {
try {
val database = PersistentFirebaseUtil.getDatabase().reference
val job = async(CommonPool) {
for (obj in promoType) {
val query = database.child("promos").child(obj).orderByChild("promoCode").equalTo(promoCodeET)
query.addListenerForSingleValueEvent(object :
ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
couponKey = dataSnapshot.key.toString()
couponFoundAtKey = dataSnapshot.children.first().key.toString()
if (couponKey.isNotEmpty())
changeUserType(couponKey, couponFoundAtKey)
flag = true
}
}
override fun onCancelled(error: DatabaseError) {
// Failed to read value
}
})
if (flag) break
}
}
job.await()
}
catch (e: Exception) {
}
finally {
if (couponKey.isEmpty()){
Toast.makeText(this@Coupon, "Invalid coupon", Toast.LENGTH_LONG).show()
}
flag = true
}
}
解决方案
我发现您的代码有几处错误:
- 你有一个
async(UI)
没有意义的外在 - 你的内部
async(CommonPool)
也没有意义,因为你的数据库调用已经是异步的 - 您在紧随
await
其后的地方使用反模式async
,使其不是真正的“异步”(但见上文,无论有没有这个,整个事情都是异步的) - 您的获取功能具有更改用户类型的副作用
- 要将结果传输给调用者,您再次使用副作用而不是返回值
您的代码应该更简单。您应该声明 a suspend fun
,其返回值为 pair (couponKey, coupon)
:
suspend fun fetchPromo(promoType: String, promoCodeET: String): Pair<String, String>? =
suspendCancellableCoroutine { cont ->
val database = PersistentFirebaseUtil.getDatabase().reference
val query = database.child("promos").child(promoType)
.orderByChild("promoCode").equalTo(promoCodeET)
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
cont.resume(
dataSnapshot
.takeIf { it.exists() }
?.let { snapshot ->
snapshot.key.toString()
.takeIf { it.isNotEmpty() }
?.let { key ->
Pair(key, snapshot.children.first().key.toString())
}
}
)
}
override fun onCancelled(error: DatabaseError?) {
if (error != null) {
cont.resumeWithException(MyException(error))
} else {
cont.cancel()
}
}
})
}
要调用此函数,launch(UI)
请在调用站点使用 a。获得非空值后更改用户类型:
launch(UI) {
var found = false
for (type in promoType) {
val (couponKey, coupon) = fetchPromo(type, "promo-code-et") ?: continue
found = true
withContext(CommonPool) {
changeUserType(couponKey, coupon)
}
break
}
if (!found) {
Toast.makeText(this@Coupon, "Invalid coupon", Toast.LENGTH_LONG).show()
}
}
你说它changeUserType
执行一些数据库操作,所以我将它们包装在一个withContext(CommonPool)
.
另请注意,我在函数外部提取了促销类型的循环。这将导致查询按顺序执行,但您可以编写不同的调用代码来实现并行查找:
var numDone = 0
var found = false
promoType.forEach { type ->
launch(UI) {
fetchPromo(type, "promo-code-et")
.also { numDone++ }
?.also { (couponKey, coupon) ->
found = true
launch(CommonPool) {
changeUserType(couponKey, coupon)
}
}
?: if (numDone == promoType.size && !found) {
Toast.makeText(this@Coupon, "Invalid coupon", Toast.LENGTH_LONG).show()
}
}
}
推荐阅读
- javascript - 文件上传失败,出现错误“503,网关错误”
- java - 如何将快速排序的每个步骤保存在java中的矩阵中?
- wordpress - 更改 WordPress 中的页脚
- html - 问题:设置图像大小
- python-3.x - 集成 AWS API Gateway 和 Web ACL
- ios - 发现和过滤蓝牙外设
- python - 在一定时间后完成对文件的操作的函数
- keras - 如何仅将样本拟合到多个输出中的一些 Keras 功能 API
- c# - “控制命令(以点 '.' 开头)不能从查询端点提供,除非它们是 .show 控制命令。”,
- python-3.x - 在 python3 中使用 EECodes 从 grib2 文件中读取温度、湿度等