带排球的异步协程
async coroutine with volley
我正在尝试将我的宠物应用程序转换为使用协程而不是回调。
我已经中途了,但我看不出如何绕过此函数中的回调。有没有办法使用异步来摆脱回调或者我爬错树了?
这是我目前拥有的:
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新手
本质上你需要将带有回调代码块的网络调用转换成一个可以从任何协程调用的挂起函数,这可以使用 suspendCoroutine 函数来完成,它基本上为你提供了一个延续对象,它可用于 return 来自您案例中响应回调内部的数据
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
。
我正在尝试将我的宠物应用程序转换为使用协程而不是回调。 我已经中途了,但我看不出如何绕过此函数中的回调。有没有办法使用异步来摆脱回调或者我爬错树了?
这是我目前拥有的:
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新手
本质上你需要将带有回调代码块的网络调用转换成一个可以从任何协程调用的挂起函数,这可以使用 suspendCoroutine 函数来完成,它基本上为你提供了一个延续对象,它可用于 return 来自您案例中响应回调内部的数据
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
。