如何在 Kotlin 中创建异步 post 请求?

How can I create an asynchronous post request in Kotlin?

我正在尝试向服务器发送 POST 请求并获取一些数据。我在主线程上尝试 运行ning 请求,但它一直给我一个错误,所以我决定使用 coroutines 到 运行 它作为异步线程。这是我目前所拥有的:

class requests{
    private val client = OkHttpClient()
    
    fun run() = runBlocking {
        launch {
            val postBody = """
        |Releases
        |--------
        |
        | * _1.0_ May 6, 2013
        | * _1.1_ June 15, 2013
        | * _1.2_ August 11, 2013
        |""".trimMargin()

            val request = Request.Builder()
                .url("https://api.github.com/markdown/raw")
                .post(postBody.toRequestBody(MEDIA_TYPE_MARKDOWN))
                .build()

            client.newCall(request).execute().use { response ->
                if (!response.isSuccessful) throw IOException("Unexpected code $response")

                println(response.body!!.string())
            }
        }
    }

    companion object {
        val MEDIA_TYPE_MARKDOWN = "text/x-markdown; charset=utf-8".toMediaType()
    }


}

当我 运行 requests().run() 我得到以下错误:

android.os.NetworkOnMainThreadException

我不确定为什么会收到此错误,我认为 coroutines 创建了一个新线程来防止这种情况发生。

runBlocking 不会切换线程,所以如果你在主线程上调用它,协程也会在主线程上启动。此方法会阻塞当前线程,因此切勿在生产中使用它:阻塞线程的性能非常低,您应该创建一个新协程并在那里启动您的代码

协程本身可以在主线程上正常工作,但您的代码 运行 可以检查当前线程,以及在这种情况下会发生什么 - 它会抛出异常

以下代码应该适合您:

class requests{
    private val client = OkHttpClient()
    private val coroutineScope = CoroutineScope(Dispatchers.Default)

    fun run()  {
        coroutineScope.launch {
            val postBody = """
        |Releases
        |--------
        |
        | * _1.0_ May 6, 2013
        | * _1.1_ June 15, 2013
        | * _1.2_ August 11, 2013
        |""".trimMargin()

            val request = Request.Builder()
                .url("https://api.github.com/markdown/raw")
                .post(postBody.toRequestBody(MEDIA_TYPE_MARKDOWN))
                .build()

            client.newCall(request).execute().use { response ->
                if (!response.isSuccessful) throw IOException("Unexpected code $response")

                println(response.body!!.string())
            }
        }
    }

    companion object {
        val MEDIA_TYPE_MARKDOWN = "text/x-markdown; charset=utf-8".toMediaType()
    }


}

另一种方法是使 run 成为一个 suspend 函数并从外部协程 运行 它 - 如果您想 return 你的电话结果