Hi, I am starting a coroutine in a viewmodelscope ...
# coroutines
x
Hi, I am starting a coroutine in a viewmodelscope triggered in the onPause state of my fragment. The coroutine just need to update a value in the data store pref. Some of my users get a nullpointer exception. I think its because of the speed of closing the fragment and the vm. My idea is to start the coroutine in a globalscope, is this a good approach? Thank you
l
GlobalScope is not a good idea in most cases. It's hard to make suggestion without the original code though. If it's a simple/fast operation, maybe launch in
NonCancellable
context? But I'm not sure that fixes the NPE
s
you could maybe update the value as soon as it changes (while the fragment is resumed) instead of waiting until the least possible moment (
onPause
)
r
If this was a repository instead of just DataStore, the solution would probably be to give that repository its own CoroutineScope — one which is “unstructured” in that it allows the coroutines to finish regardless of what screen you’re on. FWIW, I would probably be wrapping this DataStore in another type, and I would give that type its own CoroutineScope just like I would for a repository or use-case. When you need to write data, launch a coroutine from that unstructured scope instead of using a suspend function and the ViewModel’s scope.
x
The whole thing is about saving the last position of the camera position in a map fragment (updating after the value changes would be too much - on each camera movement). Here is a bit of the code: Fragment:
Copy code
override fun onPause() {
    super.onPause()
    viewModel.onMapStopping()
}
VM:
Copy code
fun onMapStopping() = viewModelScope.launch {
    preferencesManager.updateMapLocation(cameraPosition.value!!)
}
PrefManager:
Copy code
suspend fun updateMapLocation(cameraPosition: CameraPosition) {
    datastore.edit { preferences ->
        preferences[PreferenceKeys.KEY] = Gson().toJson(cameraPosition)
    }
}
It's working normally fine without problems, but some users got the exception. Any suggestions now?
r
viewModelScope
is not sufficient. Your
PrefManager
should just have its own CoroutineScope so that those writes aren’t interrupted.
x
I will try it, in that case it shouldn't be suspend and the function should launch a CoroutineScope with custom name, right? I wasn't using custom scopes for till now. How can I make it global, or non cancelable?
r
Something vaguely like this:
Copy code
class PrefsManager(
  val coroutineScope: CoroutineScope,
  val datastore: DataStore
) {

  fun updateMapLocation(cameraPosition: CameraPosition): Job {
    return coroutineScope.launch {
      datastore.edit { preferences ->
        preferences[PreferenceKeys.KEY] = Gson().toJson(cameraPosition)
      }
    }
  }
}
If you’re using Dagger or Koin, you can inject the CoroutineScope. Otherwise just initialize it yourself as a property of the class. You don’t need to make it non-cancellable or global. The scope won’t be cancelled unless you cancel it.
x
Thanks, I am using dagger. I'll give it a try!