1.
I am using:
override fun updateNotification(mediaSession: MediaSessionCompat) {
if (!PlayerService.IS_RUNNING) return
GlobalScope.launch {
notificationManager.notify(NOTIFICATION_ID, buildNotification(mediaSession))
}
}
I could use:
override fun updateNotification(mediaSession: MediaSessionCompat) {
if (!BeatPlayerService.IS_RUNNING) return
CoroutineScope(Dispatchers.IO).launch {
notificationManager.notify(NOTIFICATION_ID, buildNotification(mediaSession))
}
}
2.
I am using:
GlobalScope.launch {
while (true) {
delay(100)
mediaMediaConnection.mediaController ?: continue
val newTime = mediaMediaConnection.mediaController?.playbackState?.position
if (state == BIND_STATE_BOUND) newTime?.toInt()?.let { update(it) }
if (state == BIND_STATE_CANCELED) break
}
}
I could use:
CoroutineScope(Dispatchers.IO).launch {
while (true) {
delay(100)
mediaMediaConnection.mediaController ?: continue
val newTime = mediaMediaConnection.mediaController?.playbackState?.position
if (state == BIND_STATE_BOUND) newTime?.toInt()?.let { update(it) }
if (state == BIND_STATE_CANCELED) break
}
}
I dont see any visible difference while using GlobalScope.launch versus CoroutineScope().launch in my music app.
Can someone explain which is better to use in my context of 1 and 2
I have seen:
Why not use GlobalScope.launch?
but don't quite understand fully especially in my use case.
CodePudding user response:
Can someone explain which is better to use in my context of 1 and 2
Neither.
The problem with both of them is that they are pretty much unconstrained. They don't respect app's lifecycle which means that if your app gets closed (or user goes away from that screen) while some coroutines were running inside those scopes, they won't stop executing and will leak the coroutines(the app might even crash)
When can my app crash:
GlobalScope.launch {
fetchUserData() // --> this is a suspend function
updateUI() // e.g. progressBar.isVisible = false
}
Here if user navigates away from the screen while fetchUserData
was suspended. Then that code won't stop executing and when fetchUserData
returns, it will try to update the UI but since the screen has changed, it will throw an exception and your app will crash.
What we want is that coroutines should stop when they are no longer needed. If you use GlobalScope
you loose all that control. For the case of a custom CoroutineScope
, if you are cancelling it at the right time everything is good otherwise it's also harmful.
What's the alternative?
You can/should use the built-in scopes that android provides like lifecycleScope
and viewModelScope
. The first one follows the lifecycle of the activity (or fragment) while the second one gets cleaned up when view model is destoryed.
So, that was the general advice. Coming to your particular case,
- In your first case, you don't even need a coroutine scope because
notify
is a very simple function (neither suspend nor blocking) - In the second case, you have an infinite loop that breaks when a particular condition is met. Since you have this code inside a ViewModel, you most likely don't want it to run after the view model gets cleared. If you use
CoroutineScope()
orGlobalScope
you won't be able to control that. So you should use aviewModelScope
here so that the infinite loop stops when the work is no longer required.