暂停 kotlin Coroutine 不适用于 volley
suspending a kotlin Coroutine does not work with volley
我编写了以下(测试)函数来通过 volley 和协程与 google 地图 api 对话。遗憾的是,当使用 suspendCoroutine 调用它时,它永远不会完成。如果我使用相同的函数,删除协同程序并实现 "normal" 回调,一切正常。我有点不知所措,这是什么问题。有人能帮忙吗?
代码执行到 Log.d(LOGTAG, "AFTERAFTER"),但永远不会到达 Log.d("findNaturalLocations", "Response: " + response)
suspend fun testNaturalLocations(tag: Tag, lastKnownUserLocation:
Location): ArrayList<CLDistanceRequest> = suspendCoroutine {
continuation ->
Log.d("findNaturalLocations", "getDistanceAndTimeBetweenLocations")
var distanceRequests = ArrayList<CLDistanceRequest>()
val mapsBaseUrl = "https://maps.googleapis.com/maps/api/place/nearbysearch/"
val mapsOutputFormat = "json"
val location = "location=" + lastKnownUserLocation.latitude.toString() + "," + lastKnownUserLocation.longitude.toString()
val radius = "radius=5000"
val keyword = "keyword=Supermarket"
val name = "name=Supermarket"
val sensor = "sensor=true"
val apiKey = "key=API_KEY"
val finishedUrl = mapsBaseUrl + mapsOutputFormat + "?" + location + "&" + radius + "&" + keyword + "&" + name + "&" + sensor + "&" + apiKey
Log.d(LOGTAG, finishedUrl)
val jsObjectRequest = JsonObjectRequest(Request.Method.GET, finishedUrl, null,
Response.Listener<JSONObject> { response ->
Log.d("findNaturalLocations", "Response: " + response)
var results = response.getJSONArray("results")
// parse distanceRequests, ommitted for brevity
continuation.resume(distanceRequests)
},
Response.ErrorListener { error ->
Log.e("Error", error.localizedMessage, error)
continuation.resumeWithException(error)
}
)
Log.d(LOGTAG, "AFTER");
jsObjectRequest.setShouldCache(false)
CLGlobal.getRequestQueue().add(jsObjectRequest)
Log.d(LOGTAG, "AFTERAFTER");
}
用一个简单的回调做同样的事情完美无缺。
var i = 0;
runBlocking {
val query = async(CommonPool) {
i = this@CLTaskList.test2()
}
query.await()
}
suspend fun test2():Int = suspendCoroutine<Int> { continuation ->
Log.d("TESTTEST", "TEST2 CALLED")
test {
Log.d("TESTTEST", "CONTINUATION")
continuation.resume(it)
}
}
fun test(completionHandler: (Int) -> Unit) {
Log.d("TESTTEST", "TEST CALLED")
completionHandler(1)
}
正如您在评论中透露的那样,这就是您 运行 查询的方式:
val query = async(CommonPool) {
this@CLTaskList.testNaturalLocations(tags[0],
CLGlobal.getInstance().mLastKnownLocation!!)
}
runBlocking<Unit> { query.await() }
你已经接近做对了,但是这段代码是倒退的:
- 您将可挂起函数 运行 置于线程池中,减轻了某些工作线程的阻塞责任,直到您得到答案(它不会在意是否被阻塞);
- 您使用
runBlocking
阻塞了您的 GUI 线程。
在正确的解决方案中,您需要 async
、CommonPool
或 runBlocking
的 none,您只需要:
launch(UI) {
val result = testNaturalLocations(tags[0],
CLGlobal.getInstance().mLastKnownLocation!!)
// deal with the result right here
}
因为 testNaturalLocations
是一个可挂起的函数,它不会阻塞你的 UI 线程,当你写的回调恢复它时,你的代码只是继续到下一行, result
已分配。
我编写了以下(测试)函数来通过 volley 和协程与 google 地图 api 对话。遗憾的是,当使用 suspendCoroutine 调用它时,它永远不会完成。如果我使用相同的函数,删除协同程序并实现 "normal" 回调,一切正常。我有点不知所措,这是什么问题。有人能帮忙吗?
代码执行到 Log.d(LOGTAG, "AFTERAFTER"),但永远不会到达 Log.d("findNaturalLocations", "Response: " + response)
suspend fun testNaturalLocations(tag: Tag, lastKnownUserLocation:
Location): ArrayList<CLDistanceRequest> = suspendCoroutine {
continuation ->
Log.d("findNaturalLocations", "getDistanceAndTimeBetweenLocations")
var distanceRequests = ArrayList<CLDistanceRequest>()
val mapsBaseUrl = "https://maps.googleapis.com/maps/api/place/nearbysearch/"
val mapsOutputFormat = "json"
val location = "location=" + lastKnownUserLocation.latitude.toString() + "," + lastKnownUserLocation.longitude.toString()
val radius = "radius=5000"
val keyword = "keyword=Supermarket"
val name = "name=Supermarket"
val sensor = "sensor=true"
val apiKey = "key=API_KEY"
val finishedUrl = mapsBaseUrl + mapsOutputFormat + "?" + location + "&" + radius + "&" + keyword + "&" + name + "&" + sensor + "&" + apiKey
Log.d(LOGTAG, finishedUrl)
val jsObjectRequest = JsonObjectRequest(Request.Method.GET, finishedUrl, null,
Response.Listener<JSONObject> { response ->
Log.d("findNaturalLocations", "Response: " + response)
var results = response.getJSONArray("results")
// parse distanceRequests, ommitted for brevity
continuation.resume(distanceRequests)
},
Response.ErrorListener { error ->
Log.e("Error", error.localizedMessage, error)
continuation.resumeWithException(error)
}
)
Log.d(LOGTAG, "AFTER");
jsObjectRequest.setShouldCache(false)
CLGlobal.getRequestQueue().add(jsObjectRequest)
Log.d(LOGTAG, "AFTERAFTER");
}
用一个简单的回调做同样的事情完美无缺。
var i = 0;
runBlocking {
val query = async(CommonPool) {
i = this@CLTaskList.test2()
}
query.await()
}
suspend fun test2():Int = suspendCoroutine<Int> { continuation ->
Log.d("TESTTEST", "TEST2 CALLED")
test {
Log.d("TESTTEST", "CONTINUATION")
continuation.resume(it)
}
}
fun test(completionHandler: (Int) -> Unit) {
Log.d("TESTTEST", "TEST CALLED")
completionHandler(1)
}
正如您在评论中透露的那样,这就是您 运行 查询的方式:
val query = async(CommonPool) {
this@CLTaskList.testNaturalLocations(tags[0],
CLGlobal.getInstance().mLastKnownLocation!!)
}
runBlocking<Unit> { query.await() }
你已经接近做对了,但是这段代码是倒退的:
- 您将可挂起函数 运行 置于线程池中,减轻了某些工作线程的阻塞责任,直到您得到答案(它不会在意是否被阻塞);
- 您使用
runBlocking
阻塞了您的 GUI 线程。
在正确的解决方案中,您需要 async
、CommonPool
或 runBlocking
的 none,您只需要:
launch(UI) {
val result = testNaturalLocations(tags[0],
CLGlobal.getInstance().mLastKnownLocation!!)
// deal with the result right here
}
因为 testNaturalLocations
是一个可挂起的函数,它不会阻塞你的 UI 线程,当你写的回调恢复它时,你的代码只是继续到下一行, result
已分配。