簡體   English   中英

在kotlin中進行多次異步等待

[英]multiple async-await in kotlin

promoType = [list of string]中的obj更像是在這里運行的10個firebase查詢,查看10個特定的節點集並進一步向下。

我不確定,我是否需要對每個查詢進行異步/等待,但我想要的只有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
    }
}

我發現你的代碼有幾個問題:

  1. 你有一個外部async(UI)沒有意義
  2. 您的內部async(CommonPool)也沒有意義,因為您的數據庫調用已經是異步的
  3. 您使用反模式,您在async后立即await它,使它不是真正的“異步”(但參見上文,整個過程是異步的,有或沒有這個)
  4. 您的提取功能具有更改用戶類型的副作用
  5. 要將結果傳輸給調用者,您再次使用副作用而不是返回值

您的代碼應該更簡單。 你應該聲明一個suspend fun它的返回值是對(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)

另請注意,我在函數外部的promo類型中提取了循環。 這將導致查詢按順序執行,但您可以編寫不同的調用代碼來實現並行查找:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM