首页 > 解决方案 > 如何等待协程结束

问题描述

我在下面有一些代码。延迟(3000)只是一个长循环(或循环)的替代品。我期望循环完成println(res)后将打印“Some String”,然后启用button. 但在现实生活中println(res)打印一个空字符串并button在我单击它时同时启用。我的问题是:我如何才能等待协程结束,并且只有在协程运行完成后才能println(res)等待button.isEnabled = true.

private var res: String = ""

private suspend fun test(): String {
    delay(3000) // delay - just replacement for long loop
    return "Some String" // String received after loop
}

fun onClick(view: View) {
    res = ""
    button.isEnabled = false
    GlobalScope.launch {
        res = withContext(Dispatchers.Default) {
            test()
        }
    }
    println(res) // 1. trying to get string received after loop, but not working
    button.isEnabled = true // 2. button must be enabled after loop in cycle, but it's not waiting till end of loop
}

标签: androidkotlincoroutinekotlin-coroutines

解决方案


这里要理解的主要内容是协程中的代码默认情况下是按顺序执行的。 即协程相对于“兄弟”代码异步执行,但协程内的代码默认同步执行。

例如:

fun DoSometing () { 

coroutineA {
doSomethingA1()
doSomethingA2()
}

some additional code 

}

Corroutine A 将执行与一些附加代码相关的异步, 但 doSomethingA2 将在 doSomethingA1 完成后执行。

这意味着,在协程中,下一段代码将在前一段代码完成后执行。因此,无论您想在协程完成时执行什么,您只需将其放在该协程的末尾并声明您要在其中执行它的上下文( withContext )。

当然,如果您在协程(如另一个协程)中启动另一段异步代码,则例外。

编辑:如果你需要从协程更新 UI,你应该在主上下文中执行它,即你会有这样的东西:

GlobalScope.launch (Dispatchers.IO) {

   //do some background work
   ...
   withContext (Dispatchers.Main) { 
       //update the UI 
       button.isEnabled=true  
       ...
     }
}

推荐阅读