我正在尝试将我的宠物应用程序转换为使用协程而不是回调。我已经完成了一半,但是我看不到如何绕过这个函数中的回调。有没有一种方法可以使用异步来摆脱回调,或者我爬错了树?
这就是我到目前为止所知道的:
const val url = "https://pokeapi.co/api/v2/pokemon/"
class PokeClient {
fun getPokemonData(context: Context, successCallBack: (Pokemon) -> Unit, pokemonName: String) = runBlocking {
val queue = Volley.newRequestQueue(context)
val request = url.plus(pokemonName)
var deferredResult = async {
val stringRequest = StringRequest(Request.Method.GET, request, Response.Listener<String> { response ->
val jObj = JSONObject(response)
val imgUrl = jObj
.getJSONObject("sprites")
.getJSONObject("other")
.getJSONObject("official-artwork")
.getString("front_default")
val inputStream = URL(imgUrl).openStream()
successCallBack(Pokemon(name = jObj.getString("name"), image = BitmapFactory.decodeStream(inputStream)))
}, Response.ErrorListener {
val toast = Toast.makeText(context, "error talking to professor Oak!", Toast.LENGTH_SHORT)
toast.show()
})
queue.add(stringRequest)
}
deferredResult.await()
}
}有什么想法吗?
谢谢你,Android新手
发布于 2021-07-15 00:31:35
本质上,你需要将带有回调代码块的网络调用转换成可以从任何协程调用的挂起函数,这可以使用suspendCoroutine函数来完成,它基本上为你提供了一个coroutine对象,在你的例子中,它可以用来从响应回调中返回数据
suspend fun getPokemon() = suspendCoroutine<Pokemon> { cont ->
val queue = Volley.newRequestQueue(this)
val url = "https://pokeapi.co/api/v2/pokemon/"
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<Pokemon> { response ->
val jObj = JSONObject(response)
val imgUrl = jObj.getJSONObject("sprites")
.getJSONObject("other")
.getJSONObject("official-artwork")
.getString("front_default")
val inputStream = URL(imgUrl).openStream()
/* call continuation.resume and pass your object */
cont.resume(Pokemon(name = jObj.getString("name"), image = BitmapFactory.decodeStream(inputStream)))
},
Response.ErrorListener {
/* if network call fails then post appropriate error */
cont.resumeWithException(YourExceptoin)
})
queue.add(stringRequest)
}现在,您可以从协程调用此function并获得一个Pokemon,如下所示
runBlocking{
try { val pokeMon = getPokemon() }
catch(e: Exception) { Log.d(TAG, "Cant get pokemon") }
}注意:只使用runBlocking进行学习和探索是可以的,否则这不是一个好主意,请使用launch或async
编辑:如注释中所述,如果您需要支持取消,也可以使用suspendCancellableCoroutine (对于结构化并发,您应该这样做)。
https://stackoverflow.com/questions/68381541
复制相似问题