Difference of setValue() & postValue() in MutableLiveData
Solution 1
Based on the documentation:
Sets the value. If there are active observers, the value will be dispatched to them. This method must be called from the main thread.
Posts a task to a main thread to set the given value. If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
To summarize, the key difference would be:
setValue()
method must be called from the main thread. But if you need set a value from a background thread, postValue()
should be used.
Solution 2
All of the above answers are correct. But one more important difference. If you call postValue()
and after that you call getValue()
, you may not receive the value that you set in postValue()
. If the main thread had already set the value, then you will get the value that you posted, but if the main thread hadn't set the value yet, then you don't get the value that you posted. So be careful if you work in background threads.
Solution 3
setValue()
is called directly from caller thread, synchronously notifies observers and changes LiveData
value immediately. It can be called only from MainThread.
postValue()
uses inside something like this new Handler(Looper.mainLooper()).post(() -> setValue())
, so it runs setValue
via Handler
in MainThread. It can be called from any thread.
Solution 4
Sets the value. If there are active observers, the value will be dispatched to them.
This method must be called from the main thread.
If you need set a value from a background thread, you can use
postValue(Object)
Posts a task to a main thread to set the given value.
If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
Solution 5
This is not a direct answer to the above problem. The answers from Sagar and w201 are awesome. But a simple rule of thumb I use in ViewModels for MutableLiveData is:
private boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
private MutableLiveData<Boolean> mutVal = new MutableLiveData<>(false);
public LiveData<Boolean> getMutVal() { return this.mutVal; }
public void setMutVal(boolean val) {
if (isMainThread()) mutVal.setValue(val);
else mutVal.postValue(val);
}
Replace mutVal
with your desired value.
Related videos on Youtube
![Khemraj Sharma](https://i.stack.imgur.com/l9PyP.png?s=256&g=1)
Khemraj Sharma
Email : [email protected] LinkedIn : https://www.linkedin.com/in/khemrajsharma/ Flutter, Android, Kotlin, Java, Dart, JavaScript Just love to code Pluralsight Java Expert & Android Proficient HackerRank Java 5 Star
Updated on April 20, 2022Comments
-
Khemraj Sharma about 2 years
There are two ways that make change value of
MutableLiveData
. But what is difference betweensetValue()
&postValue()
inMutableLiveData
.I could not find documentation for same.
Here is class
MutableLiveData
of Android.package android.arch.lifecycle; /** * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method. * * @param <T> The type of data hold by this instance */ @SuppressWarnings("WeakerAccess") public class MutableLiveData<T> extends LiveData<T> { @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
-
jungledev over 5 yearsWish I could triple-upvote! Based on this, it appears it's best to use
setValue()
if possible, and cautiously use 'postValue()', only when necessary. Thanks -
w201 over 5 yearsNo, here isn't any "best" way. If you work with your LiveData from background thread you should to use postValue. Also in latest version of lifecycle components it fixed... probably.
-
Chris Nevill over 5 years"Also in latest version of lifecycle components it fixed... probably." Do you have any more information on this? Thanks
-
w201 over 5 yearsI made some tests and seems that with last version of lib everything works as it should.
-
stdout almost 5 years"only the last value would be dispatched". I can't be sure about it by reading the code. So it seems like once the first thread about to hit the inner synchronised block inside postValue(), the next CPU window can be potentially given to the thread 2 which is posting another value. Thread 2 can then complete the synchronised block and the scheduler gives the first thread a window to run itself. Now, it overrites what thread 2 has already written. Is this possible?
-
kwmt almost 5 yearsCould you show me the above concretely code? If In ViewModel, I Implemented like
noObserveLiveData.postValue("sample")
, In Activity, when I used getValue likeviewModel.noObserveLiveData.getValue
Do you mean Is it not the value that I set in postValue() ("sample")? -
19Craig over 4 yearsNice, I like this. In Kotlin I created an extension that encapsulates the smart update so the numerous value updates throughout my app are a single, consistent call.
-
starriet over 3 years@w201 when you said "with last version of lib everything works as it should", does it mean your answer is not valid anymore? ...So now we CAN get the value that we set in
postValue(...)
even if there are no observers? If that's the case, I think we should modify this answer so that people don't get confused. -
starriet over 3 yearsThanks for the nice answer. So, according to @w201's answer(if it's valid until now), the
Handler
'spost
method doesn't get called if it's not the main thread and there is no observer? -
Ufkoku over 3 yearspost is always called and value is updated inside LiveData. But if there is no observers or they are not in started state they will not be notified.
-
Ufkoku over 3 yearsThe main issue is that post updates value asynchronously, so if you called getValue() you can get old one
-
starriet over 3 yearsSo, if I call
getValue()
, I might get the old value, but maybe I can get the latest value, right? So w201 said in his/her answer that "you don't receive the value that you set in postValue()", but maybe I can receive the value that I set? -
Ufkoku over 3 years@starriet yes, you can get value which was set by postValue(). It is all about concurrency. If main thread has enough time to execute update triggered by postValue() then getValue() will return posted one. If you call getValue() too soon after postValue() and main thread had no time to execute posted update, then getValue() will return old value.
-
starriet over 3 yearsSo, if I understood correctly, setting the value has nothing to do with the existence of observers. Even if there is no observer, after the worker thread posted some value with
postValue()
, if the main thread executes setting the value, then we can get the value that we posted. Please let me know if I'm wrong. Thanks a lot :) -
TootsieRockNRoll over 3 yearsIMPORTANT NOTE: I just noticed that if you're in main thread and use postValue it will take a few more millis compared to setValue to dispatch the data. I had this happen when I fill a layout manually, with setValue it was instant but not with post
-
guybydefault almost 3 yearsNot exactly. If you are working on the main thread then setValue and postValue have a some difference: setValue will set the value and notify the observers instantly while postValue posts the task that will set the value and notify the observes later (usually in a couple of millis).
-
Turkhan Badalov over 2 yearsBasically, to deviate people from messing up with volatile keyword, they do it for you using postValue + more sophistication added.