如何在 Android 中等待 khttp (kotlin) 响应

How to wait for khttp (kotlin) response in Android

我一直在尝试使用 khttp 在 android activity 中发送一个 .jpg 文件,但未能成功。

fun sendImage(view: View) {

    try {
        var bmp = (imageView?.drawable as BitmapDrawable).bitmap
        var bos = ByteArrayOutputStream()
        bmp.compress(Bitmap.CompressFormat.JPEG, 0, bos)
        var response: Response? = null
        findViewById<TextView>(R.id.image_desc).text = "Connecting to " + SERVER_URL;

        try {
            val job=GlobalScope.launch {
                response = post(SERVER_URL, files = listOf(File(path).fileLike(name = "Image.jpg")))
            }

            findViewById<TextView>(R.id.image_desc).text = "Image contains: ${response?.text}"
        } catch (e: Exception) {
            findViewById<TextView>(R.id.image_desc).text = "Connection failed - please check fields are valid"
            findViewById<TextView>(R.id.image_desc).text = e.toString()
        }

    } catch (e: UnknownHostException) {
        findViewById<TextView>(R.id.image_desc).text = "Unknown host :("
        e.printStackTrace()
    } catch (e: IOException) {
        findViewById<TextView>(R.id.image_desc).text = "IO exceptiion :("
        e.printStackTrace()
    } catch (e: Exception) {
        findViewById<TextView>(R.id.image_desc).text = "Other exception :("
        e.printStackTrace()
    }
}

我一发送图像,image_desctextView 的文本更改为图像包含:null。我确定服务器不是问题,因为当我用这个 python 代码测试它时:

import requests

url=...
files = {'file': open('./test/cat.jpg', 'rb')}
r=requests.post(url,files=files)
print (r.text)

我在短暂的延迟后得到了想要的响应。我尝试将 sendImage 转换为挂起函数并编写 job.join() 但这会使应用程序崩溃。应该如何解决这个问题?

尝试下一个代码:

val job = GlobalScope.launch(Dispatchers.Main) {
    val postOperation = async(Dispatchers.IO) { // <- extension on launch scope, launched in IO dispatcher
        // blocking I/O operation
        post(SERVER_URL, files = listOf(File(path).fileLike(name = "Image.jpg")))
    }
    response = postOperation.await() // wait for result of I/O operation without blocking the main thread
    findViewById<TextView>(R.id.image_desc).text = "Image contains: ${response?.text}"
}

同时将下一行添加到应用程序的 build.gradle 依赖项中:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'

注意 GlobalScope 不鼓励使用,启动协同程序使用 CoroutineScope 的实例,或像 viewModelScope or lifecycleScope 这样的现有实例.


更新:

正确的方法是在 Activity:

中使用 lifecycleScope
lifecycleScope.launch { // uses Dispatchers.Main context
    val response = withContext(Dispatchers.IO) { // change context to background thread
        // blocking I/O operation
        post(SERVER_URL, files = listOf(File(path).fileLike(name = "Image.jpg")))
    }
    findViewById<TextView>(R.id.image_desc).text = "Image contains: ${response?.text}"
}