Search code examples
androidandroid-livedatakotlin-coroutinesandroid-viewmodel

LiveDataScope vs ViewModelScope in Android


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?


Solution

  • 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

    1. viewModelScope:

    Official doc says that, CoroutineScope tied to this ViewModel. This scope will be canceled when ViewModel will be cleared, i.e ViewModel.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!

    2. LiveDataScope:

    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.


    TL;DR

    Check out the liveData method,

    Doc states that, The liveData building block serves as a structured concurrency primitive between coroutines and LiveData. The code block starts executing when LiveData becomes active and is automatically canceled after a configurable timeout when the LiveData becomes inactive. If it is canceled before completion, it is restarted if the LiveData 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 a CancelationException), it is not restarted.

    I hope that make sense!