簡體   English   中英

為什么這兩種方法顯示不同的結果?

[英]Why do these two methods shows different results?

我試圖使用協程 kotlin 從 Firestore 獲取 arraylist。 我寫了兩種不同的方法來獲得相同的結果。 這些是方法

方法A

fun methodA(type: String) {
           CoroutineScope(IO).launch {
             val myList = mutableListOf<Product>()
             val job = async(IO) {
              db.collection("Products").get().addOnSuccessListener { snapShot ->
                 snapShot.forEach { subSnapShot ->
                    if (subSnapShot.exists()) {
                        if (subSnapShot["name"]?.equals(type) == true) {
                            val category = type
                            val url = subSnapShot["url"].toString()
                            val type = subSnapShot["type"].toString()
                            val item = Product(url, category, subSnapShot.id, type)
                            myList.add(item)
                        }
                    }
                }
              }
            myList
         }.await()
          temp.postValue(job)
       }
      }

方法B

 fun methodB(type: String) {
    CoroutineScope(IO).launch {
              val myList = mutableListOf<Product>()
               db.collection("Products").get().addOnSuccessListener { snapShot ->
                snapShot.forEach { subSnapShot ->
                  if (subSnapShot.exists()) {
                      if (subSnapShot["name"]?.equals(type) == true) {
                          val category = type
                          val url = subSnapShot["url"].toString()
                          val type = subSnapShot["type"].toString()
                          val item = Product(url, category, subSnapShot.id, type)
                          myList.add(item)
                      }
                  }
              }
          }.await()
        temp.postValue(myList)
    }
}

我期望從這兩種方法中得到相同的結果,但是MethodA返回一個空列表,而MethodB返回項目列表。 如果我像MethodB那樣獲取這樣的列表,我該如何修復我的MethodA

這些都不會可靠地工作。 這是一個競爭條件,您很幸運使用了 MethodB。 它不會一直成功。

問題是即使您在任務上調用await() ,回調也不一定會在await()返回之前運行。

一個監聽器被異步調用。 它下面的代碼繼續在添加它的同一線程中運行。 然后,當結果完成時,偵聽器內的代碼將在未來一段時間內運行(可能只有幾毫秒,但仍然在運行其他代碼之后)。

由於您使用的是協程,因此您應該使用await()的返回值,而不是添加偵聽器。 您還需要使用try/catch以防失敗。 然后你的代碼可以按照它出現的順序順序運行,利用協程的最佳特性之一。

在實踐中,您應該使用在適當時間取消的現有 CoroutineScope,而不是創建一次性 CoroutineScope 來啟動單個協程然后將其丟棄。 但我在這個例子中留下了這個,因為這不是你要問的。

以下是正確執行此操作的方法(CoroutineScope 部分除外):

fun methodC(type: String) {
    CoroutineScope(IO).launch {
        try { 
            db.collection("Products").get().await()
                .filter { it.exists() && it["name"]?.equals(type) == true }
                .map { subSnapShot ->
                    val category = type
                    val url = subSnapShot["url"].toString()
                    val type = subSnapShot["type"].toString()
                    Product(url, category, subSnapShot.id, type)
                }
                .let(temp::postValue)
        } catch (e: Exception) {
            Log.e(TAG, "Failed to query products.", e)
        }
    }
}

暫無
暫無

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

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