Example from Android Jetpack: LiveData
MutableLiveData Example |
---|
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 |
---|
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 aMutableLiveData
. 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.
...
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 thevalue
property ofMutableLiveData
. Which is sad that we really need to exposeMutableLiveData
, 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 exposeMutableLiveData
directly, but that you only exposeLiveData
to outside classes because that's just going to make your code much much safer.
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 |
---|---|
Don't publicly expose MutableLiveData |
---|
So you might have noticed that I've been using both this class called
MutableLiveData
andLiveData
. SoMutableLiveData
, as the name implies, isLiveData
that could be changed. And what that means is that it exposes thesetValue
andpostValue
methods.setValue
andpostValue
are just a little bit different.setValue
is meant for being called on the main thread and thenpostValue
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 usingsetValue
andpostValue
.
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 thatMutableLiveData
. 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 yourLiveData
, and everything outside of there is just observing theLiveData
.
"And also, it's exposing a MutableLiveData. Almost ... You should almost never do this." I'm not so sure about this, for one time shots, for example when wanting to show an error Toast or similar it's handy to have a public mutableLiveData(null) in your ViewModel which is observed in your activity, when you set the value the observer can show the error and then set the value to null, instead of calling another function of the ViewModel to reset the value which I would find to be too much of an overhead for nothing. And this is actually also being done in Google's codelab "Advanced Coroutines"