如何等待并正确从异步协程返回值

Kus*_*hal 5 android async-await kotlin kotlin-coroutines

function通过单击按钮来调用(非暂停)。我想function使用async协程运行一个循环并返回最后的计算值。

我的代码:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    btnCount.setOnClickListener {

        var result = GlobalScope.async { dummyFoo() }
        runBlocking {
            Toast.makeText(this@MainActivity, result.await().toString(), Toast.LENGTH_LONG).show()
        }
    }
}

private fun dummyFoo() : Int {
    var result : Int = 0
    val waitFor = CoroutineScope(Dispatchers.IO).async {
        for (i in 1..20000) {
            result++
        }
        return@async result
    }

    return result
}
Run Code Online (Sandbox Code Playgroud)

输出 :

我得到了0Toast

我要20000Toast

如何让我的代码等待循环完成并20000输出结果?

小智 7

您应该在 dummyFoo() 中使用await

private suspend fun dummyFoo() : Int {
    var result : Int = 0
    val waitFor = CoroutineScope(Dispatchers.IO).async {
        for (i in 1..20000) {
            result++
        }
        return@async result
    }
    waitFor.await()
    return result
}
Run Code Online (Sandbox Code Playgroud)

  • 我不想将 `dummyFoo()` 设置为 `suspend`。所以,我无法从中创建 `CoroutineScope()` (2认同)

Mar*_*nik 5

您似乎想要从 GUI 线程启动 CPU 密集型任务,然后在 GUI 中呈现结果。这是协程的基本用例,解决方法如下:

btnCount.setOnClickListener {
    GlobalScope.launch(Dispatchers.Main) {
        val result = withContext(Dispatchers.Default) {
            dummyFoo()
        }
        Toast.makeText(this@MainActivity, result.toString(), Toast.LENGTH_LONG).show()
    }
}
Run Code Online (Sandbox Code Playgroud)

这与通常的警告相一致,即您不应在全局范围内启动协程,而应为相关活动创建一个范围。否则,即使用户离开您的应用程序,这些后台任务也会占用 CPU。

  • 这是一个简单的修复(请参阅更新的代码),但无论如何你都不应该使用“GlobalScope”。 (3认同)