【问题标题】:Wait for all volley request in a for loop在 for 循环中等待所有凌空请求
【发布时间】:2021-11-04 14:42:03
【问题描述】:

在我的函数中,我需要返回一个列表,该列表由带有一些 Volley 请求的 for 循环填充。所以我需要等待所有这些请求都被终止,然后才能返回列表。

我认为我需要异步 CoroutineScope 来完成这项工作,但我不知道如何才能等待所有响应。

这是我的代码:

suspend fun getListOfAbility(pokemon: Pokemon) : MutableList<Ability> {
    val listOfAbility: MutableList<Ability> = emptyList<Ability>() as MutableList<Ability>
    CoroutineScope(Dispatchers.IO).launch {
        /**
         * get the pokemon json
         */
        val pokemonJsonObjectRequest = JsonObjectRequest(
            Request.Method.GET,
            "$pokemonUrl${pokemon.id}",
            null,
            {
                /**
                 * onResponse
                 *
                 * get the list of pokemon abilities
                 */
                val abilitiesJO = it.getJSONObject("abilities")
                val abilityObjectType = object : TypeToken<List<PokemonGson.AbilityObjectGson>>() { }.type
                val abilityListGson = Gson().fromJson<List<PokemonGson.AbilityObjectGson>>(abilitiesJO.toString(), abilityObjectType)
                /**
                 * for each ability listed on pokemon info get the full Ability Object
                 */
                for((index, abilityObjectGson) in abilityListGson.withIndex()) {
                    val abilityJsonObjectRequest = JsonObjectRequest(
                        Request.Method.GET,
                        abilityObjectGson.ability.url,
                        null,
                        {
                            abilityJson ->
                            /**
                             * onResponse
                             *
                             * get the full ability info
                             */
                            val abilityType = object : TypeToken<AbilityGson>() { }.type
                            val abilityGson = Gson().fromJson<AbilityGson>(abilityJson.toString(), abilityType)

                            /**
                             * fill the Ability entry of listOfAbility with the correct language
                             */
                            val ability = Ability(abilityGson, abilityListGson[index].is_hidden)

                            listOfAbility.add(ability)

                        },
                        {
                            /**
                             * onError
                             */
                            Log.d("POKEMON", "Pokemon ability error")
                        }
                    )

                    requestQueue.add(abilityJsonObjectRequest)
                }

            },
            {
                /**
                 * onError
                 */
                Log.d("POKEMON", "Pokemon request error")
            }
        )
        requestQueue.add(pokemonJsonObjectRequest)
    }

    //wait
    return listOfAbility
}

【问题讨论】:

    标签: kotlin android-volley kotlin-coroutines


    【解决方案1】:

    要在挂起函数中使用基于回调的代码,您需要使用suspendCoroutinesuspendCancellableCoroutine 将其转换为挂起函数。因此,在这种情况下,要替换创建 JSONObjectRequest 和侦听器、将其排队到 RequestQueue 并以某种方式等待它的操作,我将创建一个如下所示的挂起函数:

    suspend inline fun RequestQueue.getJSONObjectOrNull(
        method: Int,
        url: String,
        jsonRequest: JSONObject?,
        crossinline onError: (VolleyError)->Unit = {}
    ): JSONObject? = suspendCancellableCoroutine { continuation ->
        val request = JsonObjectRequest(
            method,
            url,
            jsonRequest,
            { result: JSONObject -> continuation.resume(result) },
            { error ->
                onError(error)
                continuation.resume(null)
            }
        )
        add(request)
        continuation.invokeOnCancellation { request.cancel() }
    }
    

    直接返回JSONObject结果,失败则返回null。您可以选择在错误上运行回调,以备不时之需。

    然后您可以使用它来编写函数的更顺序版本,而不是基于回调的版本。您可以使用coroutineScope { async { list.map { ... } } }.awaitAll() 的模式,使用并行协程将列表中的每一项转换为其他内容。

    这是您的函数的未经测试的版本。我让它在失败时返回一个空列表。您也可以在失败时返回 null,这可能更有用,因此调用函数可以决定在失败时执行不同的操作。

    private fun VolleyError.logDebug() {
        Log.d("POKEMON", "Pokemon request error: $this")
    }
    
    suspend fun getListOfAbility(pokemon: Pokemon): List<Ability> {
        val pokemonJsonObject = requestQueue.getJSONObjectOrNull(Request.Method.GET, "$pokemonUrl${pokemon.id}", null, VolleyError::logDebug)
    
        pokemonJsonObject ?: return emptyList()
    
        val abilitiesJO = pokemonJsonObject.getJSONObject("abilities")
        val abilityObjectType = object : TypeToken<List<PokemonGson.AbilityObjectGson>>() {}.type
        val abilityListGson: List<Wrapper> = Gson().fromJson<List<PokemonGson.AbilityObjectGson>>(
            abilitiesJO.toString(),
            abilityObjectType
        )
    
        return coroutineScope {
            abilityListGson.map {
                async {
                    requestQueue.getJSONObjectOrNull(Request.Method.GET, it.ability.url, null, VolleyError::logDebug)
                }
            }
        }
            .awaitAll()
            .filterNotNull()
            .map { abilityJson ->
                val abilityType = object : TypeToken<AbilityGson>() {}.type
                val abilityGson = Gson().fromJson<AbilityGson>(abilityJson.toString(), abilityType)
                Ability(abilityGson, abilityListGson[index].is_hidden)
            }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      • 2015-10-06
      • 1970-01-01
      • 2018-10-20
      • 2021-03-15
      • 2019-03-14
      • 2023-01-20
      相关资源
      最近更新 更多