在 Android Kotlin 中异步获取 URL

Ale*_*x S 6 android kotlin kotlin-android-extensions

因此,我正在尝试编写一个非常简单的 Android 应用程序,当按下按钮时,它会从 URL 获取响应。kotlin Android 扩展已被宣传为 Java 中所需样板文件的直接替代品,所以我尝试了一下。到目前为止,这是我尝试过的:

package com.example.susemihl.myapplication

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.runBlocking
import java.net.URL

suspend fun fetch_url(url: String): String {
    return URL(url).readText()
}

fun fetch_async(url: String, view: TextView) = runBlocking {
    val result = async(CommonPool) { fetch_url(url) }
    view.setText(result.await())
}

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mainTextView.setText("Hello there.")
        mainButton.setOnClickListener {
            mainButton.setText("Check again.")
            fetch_async("https://random-app.appspot.com/", 
                        mainTextView)
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

这间歇性地起作用,但现在完全被破坏了。单击按钮没有任何响应。打印调试显示线程已执行,但似乎挂在 readText() 调用上。我在这里做错了什么愚蠢的事情吗?

Jac*_*ong 0

我知道你的情况,这是因为你正在使用runBlocking,虽然await不会阻塞线程,但它会挂起协程,并且由于当前协程尚未完成,线程runBlocking将被阻塞等待它。

所以只需使用launc(UI)而不是runBlocking解决这个问题:

package com.example.susemihl.myapplication

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch
import java.net.URL

fun fetch_url(url: String): String {
    return URL(url).readText()
}

fun fetch_async(url: String, view: TextView) = launch(UI) {
    val result = async(CommonPool) { fetch_url(url) }
    view.text = result.await()
}

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mainTextView.text = "Hello there."
        mainButton.setOnClickListener {
            mainButton.text = "Check again."
            fetch_async("https://jacksgong.com", mainTextView)
        }

    }
}
Run Code Online (Sandbox Code Playgroud)