在Kotlin的suspendCoroutine中,AndroidNetworking永远不会返回

在Kotlin的suspendCoroutine中,AndroidNetworking永远不会返回,android,kotlin,coroutine,kotlinx.coroutines,Android,Kotlin,Coroutine,Kotlinx.coroutines,我正在试验新的协同程序,并试图通过一些丑陋的AndroidNetworking api请求将它们合并到现有的项目中 所以我当前的api请求正在使用这样的回调 fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) { AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestL

我正在试验新的协同程序,并试图通过一些丑陋的AndroidNetworking api请求将它们合并到现有的项目中

所以我当前的api请求正在使用这样的回调

fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
  AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
    override fun onResponse(response: JSONObject) { ... }
    override fun onError(error: ANError) { ... }
  }
}
fun someFunction() = runBlocking {
  async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
  Something().getSomethingFromBackend {something
    ...
    it.resume(something)
  }
}
现在我正试图合并这样的合作项目

fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
  AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
    override fun onResponse(response: JSONObject) { ... }
    override fun onError(error: ANError) { ... }
  }
}
fun someFunction() = runBlocking {
  async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
  Something().getSomethingFromBackend {something
    ...
    it.resume(something)
  }
}
如您所见,我正在尝试在一个协程中运行
callGetSomething
,一旦到了,就暂停协程,直到异步API返回

我的问题是,它永远不会回来。即使我在
onResponse
onError
等中调试,它也永远不会从后端返回

但是如果我删除
=suspendCoroutine
,它会工作,至少会返回,但是等待不会在corse下工作,因为执行将继续

如何解决这个问题,使
await()
实际等待异步调用回调


非常感谢

试试这样的方法:

fun someFunction() {
    val jsonObject: JSONObject? = runBlocking {
        callGetSomething()
    }
    // do something with jsonObject
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
    Something().getSomethingFromBackend { response, error ->
        it.resume(response)
    }
}

试着这样做:

fun someFunction() {
    val jsonObject: JSONObject? = runBlocking {
        callGetSomething()
    }
    // do something with jsonObject
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
    Something().getSomethingFromBackend { response, error ->
        it.resume(response)
    }
}

您的主要问题是您试图使用
runBlocking
,这取消了您为项目引入异步网络库和协同路由所做的所有工作。如果您在等待结果时确实想要阻塞,那么只需使用阻塞网络调用即可

如果要继续使用异步网络操作,请忘记阻塞
someFunction
,直接从
launch
块使用
callGetSomething

override fun onSomeEvent(...) {
   this.launch {
     val result = callGetSomething(...)
     // use the result, you're on the GUI thread here
   }
}

以上假设您的
是一个
活动
片段
视图模型
或实现
协同场景
的类似对象。查看它以了解如何实现这一点。

您的主要问题是,您试图使用
运行阻塞
,这取消了您为在项目中引入异步网络库和协同路由所做的所有工作。如果您在等待结果时确实想要阻塞,那么只需使用阻塞网络调用即可

如果要继续使用异步网络操作,请忘记阻塞
someFunction
,直接从
launch
块使用
callGetSomething

override fun onSomeEvent(...) {
   this.launch {
     val result = callGetSomething(...)
     // use the result, you're on the GUI thread here
   }
}

以上假设您的
是一个
活动
片段
视图模型
或实现
协同场景
的类似对象。看看它,看看如何做到这一点。

好的,谢谢大家的帮助。 我将解释我是如何发现这个问题的,以及我是如何解决它的

在详细研究了回调和协同路由之后,我决定在回调期间记录线程名称,如下所示
Log.d(“标记”,“执行线程:”+thread.currentThread().name)

这使我认识到,所有回调(错误和成功)实际上都在主线程上运行,而不是在我为其设置的协程上运行

因此,我的协同程序中的代码在
D/TAG:Execution-thread:DefaultDispatcher-worker-1
中运行,但回调在
D/TAG:Execution-thread:main
上运行

解决方案

  • 避免
    runBlocking
    :这将阻塞主线程,在这种情况下,这就是回调永远不会返回的原因

  • 启动协同程序时使用
    Dispatchers.Main
    ,这样我就可以在UI中实际使用返回的值

  • suspendCoroutine
    与它的
    resume()
    resumeWithException
    一起使用(谢谢@Sergey)

  • 示例

    fun someFunction() {
      GlobalScope.launch(Dispatchers.Main) {
        result = GlobalScope.async { callGetSomething() }.await()
        ...
      }
    }
    
    suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
      Something().getSomethingFromBackend {something
        ...
        it.resume(something)
      }
    }
    

    好的,谢谢大家的帮助。 我将解释我是如何发现这个问题的,以及我是如何解决它的

    在详细研究了回调和协同路由之后,我决定在回调期间记录线程名称,如下所示
    Log.d(“标记”,“执行线程:”+thread.currentThread().name)

    这使我认识到,所有回调(错误和成功)实际上都在主线程上运行,而不是在我为其设置的协程上运行

    因此,我的协同程序中的代码在
    D/TAG:Execution-thread:DefaultDispatcher-worker-1
    中运行,但回调在
    D/TAG:Execution-thread:main
    上运行

    解决方案

  • 避免
    runBlocking
    :这将阻塞主线程,在这种情况下,这就是回调永远不会返回的原因

  • 启动协同程序时使用
    Dispatchers.Main
    ,这样我就可以在UI中实际使用返回的值

  • suspendCoroutine
    与它的
    resume()
    resumeWithException
    一起使用(谢谢@Sergey)

  • 示例

    fun someFunction() {
      GlobalScope.launch(Dispatchers.Main) {
        result = GlobalScope.async { callGetSomething() }.await()
        ...
      }
    }
    
    suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
      Something().getSomethingFromBackend {something
        ...
        it.resume(something)
      }
    }
    

    谢谢@Sergey,但它不起作用,
    AndroidNetworking.get正在调用,协同程序正在等待,但回调从未被调用。没有响应,没有错误,什么都没有…谢谢@Sergey,但它不工作,
    AndroidNetworking.get正在调用,协同程序正在等待,但从未调用回调。没有响应,没有错误,什么都没有…你确定总是调用
    getSomethingFromBackend
    回调吗?另外,如果
    someFunction
    和回调应该从同一个线程调用,那么它就不会发生,因为你用
    runBlocking
    阻止了它,你确定总是调用
    getSomethingFromBackend
    回调吗?另外,如果
    someFunction
    和回调应该从同一个线程调用,那么它就不会发生,因为你用
    runBlocking
    阻止了它