I was reading how to use coroutines here https://developer.android.com/topic/libraries/architecture/coroutines. What makes me confused about is the difference between LiveDataScope
and ViewModelScope
. It sounds like ViewModelScope
takes care of lifecycle automatically and you can do network request in the block. When data received from server, post the value to livedata
. but then when I continued to read, there's another topic about LiveDataScope
which seems redundant to me since you can already accomplish the same result by using ViewModelScope
with livedata
. What is the main difference between those two? and when should I choose to use one over the other?
Note: This might be late answer for this topic if Author of OP already has understanding about this, But providing some pointers for the referencing comment of @IgorGanapolsky.
Let's see what is the main difference between viewModelScope & LiveDataScope
Official doc says that,
CoroutineScope
tied to thisViewModel
. This scope will be canceled whenViewModel
will be cleared, i.eViewModel.onCleared
is called
Meaning that coroutine scope is tied to ViewModel, and once ViewModel gets cleared this scope gets destroyed by cancelling all child coroutine jobs.
Basically, in MVVM pattern we use ViewModel
tied to a particular Activity/Fragment
. So once that Activity/Fragment
gets destroyed, its ViewModel
reaches a cleared state. Thus, it cancels all incomplete jobs started by viewModelScope
, throwing CancellationException
.
So a usecase of viewModelScope
is: inside ViewModel
when you've got any suspended function to be called and need a CoroutineScope
, inspite of making new one you can directly use this one out of the box from viewodel-ktx library.
class SomeViewModel: ViewModel() {
fun someFunction() {
viewModelScope.launch {
callingSomeSuspendedFun()
callingAnotherSuspendedFun()
}
}
}
Note that you don't need to explicitly override onCleared()
method of ViewModel
to cancel the scope, it does automatically for you, cheers!
Now speaking of LiveDataScope
, it's actually an interface provided to build better support for LiveData/CoroutineLiveData
that can have CoroutineScope
out of the box! use livedata-ktx version
Now imagine a situation that you're having a MVVM pattern and wanted to return LiveData
from repository to view model. your repository also contains some suspended functions and some coroutine scope.
In that situation when you do some suspended method calls & return the result as live data, there would be some extra work. you'll need transform your data to particular live data after getting it as result. see the example below:
class SomeRepository {
suspended fun someApiCall() : LiveData<Result> {
val result = MutableLiveData<Result>()
someCoroutineScope.launch {
val someData = someOtherCallToGetResult()
result.postValue(someData)
}
return result
}
}
Imagine you had to write above code block due to LiveData
didn't had any support for Coroutines ... but until now!
Now you can directly use liveData { }
function that returns you LiveData
object giving you scope of LiveDataScope
in such a way that you can continue your suspended work and emit the result at the same level rather than getting it messy way like above. So above code block can now optimized by following code or better:
class SomeRepository {
suspended fun someApiCall() : LiveData<Result> {
return liveData<Result> {
val someData = someOtherCallToGetResult()
emit(someData)
}
}
}
So use case of liveData would be at repository level when using MVVM pattern if you expose LiveData to viewmodel from respository rather than creating new inside viewmodel. Please note that there's no thumb rule about liveData
method shouldn't be used at viewmodel directly. You can if you want to avoid viewModelScope
completely.
Check out the liveData method,
Doc states that, The
liveData
building block serves as a structured concurrency primitive between coroutines andLiveData
. The code block starts executing whenLiveData
becomes active and is automatically canceled after a configurable timeout when theLiveData
becomes inactive. If it is canceled before completion, it is restarted if theLiveData
becomes active again. If it completed successfully in a previous run, it doesn't restart. Note that it is restarted only if canceled automatically. If the block is canceled for any other reason (e.g. throwing aCancelationException
), it is not restarted.
I hope that make sense!