Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 349
user1865027 Avatar asked Aug 28 '19 19:08

user1865027


People also ask

How does a ViewModelScope work?

viewModelScope contributes to structured concurrency by adding an extension property to the ViewModel class that automatically cancels its child coroutines when the ViewModel is destroyed.

What is ViewModelScope in Android?

A ViewModelScope is defined for each ViewModel in your app. Any coroutine launched in this scope is automatically canceled if the ViewModel is cleared. Coroutines are useful here for when you have work that needs to be done only if the ViewModel is active.

What is LiveDataScope?

The LiveDataScope is used for emitting values in the scope of a LiveData object. This means that as long as the LiveData object is alive and there are subscribers that coroutine will work, however once all the subscribers are out the coroutine will stop.


2 Answers

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!

like image 69
Jeel Vankhede Avatar answered Sep 29 '22 19:09

Jeel Vankhede


The names imply what they actually are:

A ViewModelScope is defined for each ViewModel in your app. Any coroutine launched in this scope is automatically canceled if the ViewModel is cleared.

This means that you can do some tasks(like continuous processing) in a coroutine that is in the scope of the ViewModel. The advantage is that you don't have to care anymore when the ViewModel will be stopped to stop your coroutine (this is a big pain when working with global things like java threads). The lifecycle of the ViewModel is related to when an activity is ended.

The LiveDataScope is used for emitting values in the scope of a LiveData object. This means that as long as the LiveData object is alive and there are subscribers that coroutine will work, however once all the subscribers are out the coroutine will stop. This coroutine also restarts once the LiveData is active again.

Basically these are 2 coroutine contexts each responsible for the lifecycle of its element.

PS:

It sounds like ViewModelScope takes care of lifecycle automatically and you can do network request in the block.

First of all, network requests cannot be done from the Main thread, you usually do them from IO scope, you can read more here. The second thing is that you should take a look at the lifecycle of the ViewModel compared to Activity if you want to understand why LiveDataScope is usually combined with ViewModelScope, you can read about that here.

The short answer to your question is that you cannot be sure that the view is created from the ViewModelScope so if you want to push some updates to UI you should push them as long as someone is subscribed to LiveData, this is where the LiveDataScope comes into play.

like image 36
Daniel Avatar answered Sep 29 '22 19:09

Daniel