I am sharing an ActivityScoped viewModel between multiple Fragments in my current Android application.
The viewModel employs Coroutine Scope viewModelScope.launch{}
My issue is the .launch{}
only works until the owning ViewModel
onCleared()
method is called.
Is this how ViewModel scoped coroutines are supposed to work?
Is there an approach I can use to "Reset" the viewModelScope so that .launch{} works following the onCleared() method being called?
heres my code::
Fragment
RxSearchView.queryTextChangeEvents(search)
.doOnSubscribe {
compositeDisposable.add(it)
}
.throttleLast(300, TimeUnit.MILLISECONDS)
.debounce(300, TimeUnit.MILLISECONDS)
.map { event -> event.queryText().toString() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { charactersResponse ->
launch {
viewModel.search(charactersResponse.trim())
}
}
. . .
override fun onDetach() {
super.onDetach()
viewModel.cancelSearch()
compositeDisposable.clear()
}
ViewModel
suspend fun search(searchString: String) {
cancelSearch()
if (TextUtils.isEmpty(searchString)) {
return
}
job = viewModelScope.launch {
repository.search(searchString)
}
}
fun cancelSearch() {
job?.cancelChildren()
}
. . .
override fun onCleared() {
super.onCleared()
repository.onCleared()
}
What am I doing wrong?
UPDATE
If I amend my launch code to this
job = GlobalScope.launch {
repository.search(searchString)
}
It solves my issue, however is this the only way to achieve my desired result?
I was under the impression GlobalScope
was "Bad"
Add a CoroutineScope to your ViewModel by creating a new scope with a SupervisorJob that you cancel in the onCleared () method. The coroutines created with that scope will live as long as the ViewModel is being used. See following code:
When the ViewModel is cleared, it executes the method clear () before calling the onCleared () method that we would’ve had to override otherwise. In the clear () method the ViewModel cancels the Job of the viewModelScope. The full ViewModel code is also available but we are just focusing on the parts we are interested in:
That’s why viewModelScope is of type CloseableCoroutineScope that extends CoroutineScope overriding the coroutineContext and implements the Closeable interface. Dispatchers.Main.immediate is set as the default CoroutineDispatcher for viewModelScope.
AndroidX lifecycle v2.1.0 introduced the extension property viewModelScope to the ViewModel class. It manages the coroutines in the same way we were doing in the previous section.
following a cal to onCleared() my viewModelScoped cororoutine Launch stops executing
That's a feature, not a bug.
Once the ViewModel
is cleared, you should not be doing anything in that ViewModel
or whatever its LifecycleOwner
was. All of that is now defunct and should no longer be used.
however is this the only way to achieve my desired result?
The correct solution is to get rid of the code from the ViewModel
. If you are expecting some background work to go past the lifetime of an activity or fragment, then that code does not belong in the activity/fragment or its associated viewmodels. It belongs in something that has a matching lifetime to the work that you are trying to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With