kotlin中的多个异步等待
multiple async-await in kotlin
promoType 中的对象 = [字符串列表]
它更像是 10 个 firebase 查询 运行 在这里,查看 10 个特定的节点集并进一步向下。
我不确定,我是否需要对每个查询进行异步/等待,但我想要的是 运行 这些查询中的 10 个,然后让我确定是否有优惠券密钥是否为空。我只想显示输入的优惠券是否正确。
进一步,在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)
也没有意义,因为你的数据库调用已经是异步的
- 你在
async
之后立即 await
使用了反模式,使其不是真正的 "async" (但见上文,无论有没有这个,整个事情都是异步的)
- 您的抓取功能具有更改用户类型的副作用
- 要将结果传输给调用者,您再次使用副作用而不是 return 值
您的代码应该更简单。您应该声明一个 suspend fun
其 return 值是对 (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)
。获得非空值后更改用户类型:
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()
}
}
}
promoType 中的对象 = [字符串列表] 它更像是 10 个 firebase 查询 运行 在这里,查看 10 个特定的节点集并进一步向下。
我不确定,我是否需要对每个查询进行异步/等待,但我想要的是 运行 这些查询中的 10 个,然后让我确定是否有优惠券密钥是否为空。我只想显示输入的优惠券是否正确。
进一步,在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)
也没有意义,因为你的数据库调用已经是异步的 - 你在
async
之后立即await
使用了反模式,使其不是真正的 "async" (但见上文,无论有没有这个,整个事情都是异步的) - 您的抓取功能具有更改用户类型的副作用
- 要将结果传输给调用者,您再次使用副作用而不是 return 值
您的代码应该更简单。您应该声明一个 suspend fun
其 return 值是对 (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)
。获得非空值后更改用户类型:
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()
}
}
}