【问题标题】:Kotlin: How to perform an async function and wait for it to finish?Kotlin:如何执行异步函数并等待它完成?
【发布时间】:2019-11-07 20:20:03
【问题描述】:

我正在用 Kotlin 编写我的第一个应用程序,所以我对此很陌生。它执行的功能之一是从 API 读取内容,然后根据结果更新屏幕。

我用协程尝试了很多东西,但似乎没有任何效果。

例如,我有这样的事情:

private fun readAPI() {
    runBlocking {
        fun rAPI() = async {
            val api = "..."
            result = URL(api).readText()
        }
        println(tag, "Result: " + rAPI().await())
    }
}

还有很多不同的方法。似乎没有任何效果。在上述情况下,我得到一个异常“android.os.NetworkOnMainThreadException”。

到目前为止唯一有效的是使用 OkHttp3 的东西,如下所述:https://rstopup.com/como-hacer-una-solicitud-a-la-api-de-kotlin.html(它是西班牙语,但你会明白的),它有效,它带来了 API 响应,我解析它,填写我的sqlite3数据库等等。但是,由于我不知道 API 何时结束,我无法更新屏幕控件。如果我尝试连续执行此操作,我会得到一个异常,即只有启动活动的线程才是可以更新活动的线程或类似的东西。

我已经看过并关注了很多关于挂起函数、启动等的教程,他们试图模仿 delay() 的 API 调用,这些教程完美运行,直到我尝试做一个真正的 API打电话。

那么,您能否指出一个完整的示例,说明如何使用 Kotlin 调用 API,然后更新一些屏幕元素?

编辑 我正在编辑通过 val 改变乐趣:

runBlocking {
  val rAPI = async {
    val api = "..."
    URL(api).readText()
  }
  Log.w(tag, rAPI.await())
}

我得到了“android.os.NetworkOnMainThreadException”异常。

【问题讨论】:

  • 代替runBlocking试试GlobalScope.launch(Dispatchers.Main)
  • 我也试过了:(
  • 会发生什么?另外 - 这个result 变量是什么?此时您的async 任务没有返回任何内容。为什么要声明fun rApi() 而不是val rApi
  • 否则,你可以创建一个新的线程 T,调用你的 API 并在里面管理回调,然后用 T.join() 等待结束
  • @Pawel 我刚刚编辑了问题以显示错误

标签: android kotlin


【解决方案1】:

既然你想使用coroutine-async的方式,你必须告诉主线程等待你。您需要使用suspend 函数或块来执行此操作。

GlobalScope.launch {
    suspend {
        Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
        delay(10000)
        withContext(Dispatchers.Main) {
            Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
        }
    }.invoke()
}

结果日志

09:36:09.500 D/: #runs on DefaultDispatcher-worker-1
// 10 seconds later
09:36:19.678 D/: #runs on main 

我认为这应该可以解决问题。

但是我建议您通过将回调(带有 onSuccess 和 onFail 或其他东西)传递给它来了解如何使用 OkHttp/Volley。 或Retrofit2RxJava 来处理这些问题。

编辑 对于Module with the Main dispatcher had failed to initialize 错误,将withContext() 行替换为此

withContext(Handler(Looper.getMainLooper()).asCoroutineDispatcher())

编辑 现在不使用 RxJava,使用 liveData/LiveEvent 来实现观察者模式

【讨论】:

  • 我试过这个并得到java.lang.IllegalStateException: Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android'
  • 尝试通过添加依赖来使用coroutineimplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
  • 好的,我添加了那个依赖项(我以为我有),现在我得到了java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize
  • 我有你提到的那个,我还得加"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1"
  • 我更新了可能解决错误的答案,建议使用最新的coroutines-core 版本。
【解决方案2】:

在 Kotlin 中,您可以将回调转换为协程,如本代码实验室 https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#6 中所述

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 2021-11-26
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    相关资源
    最近更新 更多