简体   繁体   English

暂停Kotlin Coroutine不适用于凌空抽射

[英]suspending a kotlin Coroutine does not work with volley

I wrote following (test) function to talk to the google maps api via volley and with coroutines. 我编写了以下(测试)函数,通过截击和协同程序与Google Maps api进行通信。 Sadly it never finishes when calling it with the suspendCoroutine. 可悲的是,用suspendCoroutine调用它时,它永远不会完成。 If I use the same function, drop the coroutine stuff and implement a "normal" callback, everything works fine. 如果我使用相同的功能,则删除协程程序内容并实现“正常”回调,则一切正常。 I am kind of at a loss whats the problem here. 我有点茫然,这里的问题是什么。 Is anybody able to help? 有人能帮忙吗?

Code executes until Log.d(LOGTAG, "AFTERAFTER"), but never reaches Log.d("findNaturalLocations", "Response: " + response) 代码将执行到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");
}

Doing the same with a simple callback works flawlessly. 用一个简单的回调做同样的事情是完美的。

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)
}

As you reveal in your comment, this is how you run the query: 正如您在评论中所揭示的,这是运行查询的方式:

val query = async(CommonPool) { 
    this@CLTaskList.testNaturalLocations(tags[0], 
         CLGlobal.getInstance().mLastKnownLocation!!) 
} 
runBlocking<Unit> { query.await() }

You are close to getting it right, but this piece of code is all backwards: 您几乎已经做好了准备,但是这段代码全都倒退了:

  1. You let the suspendable function run in a thread pool, relieving some worker thread of the duty to block until you get your answer (it wouldn't care if it's blocked); 您可以让suspableable函数在线程池中运行,从而减轻某些工作线程在获得答案之前有阻塞的责任(它不在乎是否被阻塞了)。
  2. You block your GUI thread with runBlocking . 您可以使用runBlocking阻止GUI线程。

In the correct solution you need none of async , CommonPool or runBlocking , all you need is this: 在正确的解决方案中,您不需要asyncCommonPoolrunBlocking ,您所需runBlocking就是:

launch(UI) {
    val result = testNaturalLocations(tags[0], 
       CLGlobal.getInstance().mLastKnownLocation!!)
    // deal with the result right here
}

Since testNaturalLocations is a suspendable function, it's not blocking your UI thread, and when the callback you wrote resumes it, your code simply goes on to the next line, with result assigned. 由于testNaturalLocations是一个可testNaturalLocations的函数,因此它不会阻塞您的UI线程,并且当您编写的回调恢复它时,您的代码将直接转到下一行,并分配result

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM