Difference of setValue() & postValue() in MutableLiveData

87,852

Solution 1

Based on the documentation:

setValue():

Sets the value. If there are active observers, the value will be dispatched to them. This method must be called from the main thread.

postValue():

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

setValue()

Sets the value. If there are active observers, the value will be dispatched to them.

This method must be called from the main thread.

postValue

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.

Share:
87,852

Related videos on Youtube

Khemraj Sharma
Author by

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 &amp; Android Proficient HackerRank Java 5 Star

Updated on April 20, 2022

Comments

  • Khemraj Sharma
    Khemraj Sharma about 2 years

    There are two ways that make change value of MutableLiveData. But what is difference between setValue() & postValue() in MutableLiveData.

    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
    jungledev over 5 years
    Wish 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
    w201 over 5 years
    No, 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
    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
    w201 over 5 years
    I made some tests and seems that with last version of lib everything works as it should.
  • stdout
    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
    kwmt almost 5 years
    Could you show me the above concretely code? If In ViewModel, I Implemented like noObserveLiveData.postValue("sample"), In Activity, when I used getValue like viewModel.noObserveLiveData.getValue Do you mean Is it not the value that I set in postValue() ("sample")?
  • 19Craig
    19Craig over 4 years
    Nice, 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
    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
    starriet over 3 years
    Thanks for the nice answer. So, according to @w201's answer(if it's valid until now), the Handler's post method doesn't get called if it's not the main thread and there is no observer?
  • Ufkoku
    Ufkoku over 3 years
    post 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
    Ufkoku over 3 years
    The main issue is that post updates value asynchronously, so if you called getValue() you can get old one
  • starriet
    starriet over 3 years
    So, 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
    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
    starriet over 3 years
    So, 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
    TootsieRockNRoll over 3 years
    IMPORTANT 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
    guybydefault almost 3 years
    Not 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
    Turkhan Badalov over 2 years
    Basically, to deviate people from messing up with volatile keyword, they do it for you using postValue + more sophistication added.