Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Don't expose MutableLiveData

Don't expose MutableLiveData

Example from Android Jetpack: LiveData

MutableLiveData Example
MutableLiveData Example

Fun with LiveData (Android Dev Summit '18)

Transformation Setup

The third item is about where and when to create your transformations and this is all about wiring. It's similar to when you create a circuit. You lay down your components and you wire everything up. And for a known set of inputs you're going to have a known set of outputs. You don't unplug a wire while it's in operation and plug it somewhere else, right?

This is exactly what this view model is doing. Lots of horrible things happening in this view model, by the way. For starters ...

Don't do this
screen shot 2018-12-21 at 9 31 03 am

B: You should [show] "don't do this" on this slide

A: It says "don't do this", literally.

B: I'm sure someone will copy/paste it and blame us for recommending it.

A: That's the standard way of doing it.

A: So first, it's exposing itemData, which is a variable. It's a [var] not a [val]. And also, it's exposing a MutableLiveData. Almost ... You should almost never do this. Two-way DataBinding is an exception to this, maybe. You should always expose something that is immutable so your observers can't change it.

...

Example of two-way DataBinding

And because we are using this property for two-way DataBinding, we need to expose it as MutableLiveData, because otherwise the layout won't be able to access the value property of MutableLiveData. Which is sad that we really need to expose MutableLiveData, but hey, if it's gonna save us some time and effort, why not? However, if you're aren't using two-way DataBinding, I would always suggest that you don't expose MutableLiveData directly, but that you only expose LiveData to outside classes because that's just going to make your code much much safer.

Lifecycle, LiveData, ViewModels - The inner wiring by Florina Muntenescu, Google EN

So, the class that would help you set these values to the LiveData is the MutableLiveData. You would use the postValue method to set the values on a background thread and setValue when you're setting the values from the main thread.

So, especially if you're using Kotlin, something that I don't like its to expose this Mutable object to the outside of the class. So what I prefer to do is to expose the LiveData object and use a backing field that is a MutableLiveData. So like this, I ensure that only the class that I'm working in can change the LiveData, so I'm still keeping this immutability principle.

Don't do this Do this
screen shot 2018-12-21 at 9 56 21 am screen shot 2018-12-21 at 9 56 41 am

droidcon NYC 2017 - ViewModels, LiveData and Lifecycles, oh my!

Don't publicly expose MutableLiveData
screen shot 2018-12-21 at 12 03 17 pm

So you might have noticed that I've been using both this class called MutableLiveData and LiveData. So MutableLiveData, as the name implies, is LiveData that could be changed. And what that means is that it exposes the setValue and postValue methods. setValue and postValue are just a little bit different. setValue is meant for being called on the main thread and then postValue can be called from a background thread.

The actual LiveData class is sort of read-only in that you can't call, you can't change what's it using setValue and postValue.

A general rule of thumb is that you'll only ever publicly expose LiveData outside of the view model. Whereas inside of the view model you could use that MutableLiveData. So by using this encapsulation you're kind of ensuring that the view model is always the one that's doing all the editing and processing of your LiveData, and everything outside of there is just observing the LiveData.

@AdamSHurwitz

This comment has been minimized.

Copy link

@AdamSHurwitz AdamSHurwitz commented Mar 30, 2019

Fantastic organization of best practice notes across various talks! This is exactly what I was looking for in terms of seeing more details after watching the 2018 Android Summit discussion, Fun with LiveData.

I understand the need for creating getter and setter points for LiveData in the ViewModel. However, I am looking to understand how the get() syntax works.

ie:

val isRealtime: LiveData<Boolean>
    get() = _isRealtime
private val _isRealtime = MutableLiveData<Boolean>()

Here is a good explanation on Stackoverflow: How Does Android LiveData get() syntax work?

get() is not related to Android.

val isRealtime: LiveData<Boolean>
    get() = _isRealtime

Here, get() is overriding the automatically-generated Kotlin getter function for the isRealtime property. So, instead of returning its own value, it returns the value of _isRealtime.
Personally, I recommend simpler syntax:

private val _isRealtime = MutableLiveData<Boolean>()
val isRealtime: LiveData<Boolean> = _isRealtime

The objective of either of these is to keep the mutability private, so consumers of this class do not accidentally update the MutableLiveData themselves.

@igorwojda

This comment has been minimized.

Copy link

@igorwojda igorwojda commented May 15, 2020

I find this method the best - mainly because less typing (better working code completion)

private val mutableLiveData = MutableLiveData<State>()
val liveData = _liveData.asLiveData()

fun <T> MutableLiveData<T>.asLiveData() = this as LiveData<T>

More ways here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment