I have some code below. Delay (3000) is just replacement for a long loop (or cycle). I’m expecting that after completion of loop println(res)
will print “Some String” and then enable button
. But in real life println(res)
prints an empty string and button
became enabled at same time when I click it.
My question is: how I can wait for end of a coroutine and only after completion of the coroutine run println(res)
and 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
}
The main thing to understand here is that code within coroutine is by default executed sequentially. I.e. coroutine is executed asynchronously in relation to "sibling" code, but code within coroutine executes synchronously by default.
For example:
fun DoSometing () {
coroutineA {
doSomethingA1()
doSomethingA2()
}
some additional code
}
Corroutine A will execute async in relation to some additional code but doSometingA2 will be executed after doSomethingA1 is done.
That means, that within a coroutine every next piece of code will be executed after the previous one is done. So, whatever you want to execute when coroutine is done, you just put at the end of that coroutine and declare context (withContext) in which you want to execute it.
The exception is of course if you start another async piece of code within coroutine (like another coroutine).
EDIT: If you need to update UI from the coroutine, you should execute that on the main context, i.e. you'll have something like this:
GlobalScope.launch (Dispatchers.IO) {
//do some background work
...
withContext (Dispatchers.Main) {
//update the UI
button.isEnabled=true
...
}
}