I need to make some function in UI thread but after delay. I need the delay to not block the main thread. Fox example I have function makeSmthInMainThread()
which I want to call in main thread after delay.
Here is my code:
GlobalScope.launch {
delay(3000)
makeSmthInMainThread()
}
Can you please tell me in this case the function will be executed in the main thread? Or do I need to wrap it in withContext(Dispatchers.Main)
?
Perhaps in this case it is better to use Handler()
and postDelayed
?
Please, help me.
CodePudding user response:
You need to use launch(Dispatchers.Main)
or withContext(Dispatchers.Main)
to execute the function in the Main Thread. By default GlobalScope.launch
runs in a Worker Thread. But be careful, GlobalScope
is a delicate API, please read the docs before using it, it can create resource and memory leaks. Consider using viewModelScope
property in ViewModel
class or lifecycleScope
property in Activity
/Fragment
to launch coroutines.
CodePudding user response:
Yes, you have to specify the Dispatcher, GlobalScope is not MainThread.
GlobalScope.launch {
delay(3000)
withContext(Dispatchers.Main.immediate) {
makeSmthInMainThread()
}
}
CodePudding user response:
GlobalScope by default uses a background thread from Dispatchers.Default, so it will fail unless you use .launch(Dispatchers.Main) {
or wrap the main thread code in withContext(Dispatchers.Main) { }
.
But GlobalScope is not suitable for a coroutine that does anything to any members of your Activity (properties or functions of your Activity), because GlobalScope coroutines do not automatically get cancelled when your Activity goes off screen. Your coroutine will leak the activity.
Use lifecycleScope.launch
so it will automatically cancel the coroutine if your Activity is destroyed, and it uses the main thread by default:
lifecycleScope.launch {
delay(1000)
doSomethingThatMustBeDoneOnMainThread()
}
If you did use Handler and postDelayed
, you would still have the problem with leaking the Activity. The appropriate solution there would be to keep a reference to your Handler in a property and clear all its messages in onDestroy()
. Likewise, with GlobalScope, you could keep your launched coroutine in a Job?
property and cancel it in onDestroy()
to avoid leaking the activity.
Since lifecycleScope
does this automatically, it's the simpler technique.