Difference of setValue postValue in MutableLiveData
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
setValue() and postValue() both update a MutableLiveData, but they do not behave the same way. The short version is that setValue() updates on the main thread immediately, while postValue() schedules a main-thread update from any thread and can merge multiple pending updates into one visible delivery.
Use setValue() on the Main Thread
setValue() is the direct update path. It must be called on the main thread, and active observers are notified as part of the main-thread execution flow.
This is the right choice when you are already on the UI thread, such as inside a click listener, fragment lifecycle method, or other main-thread callback.
If you call setValue() from a background thread, it is a usage error.
Use postValue() From Background Work
postValue() is designed for background threads. It posts the update back to the main thread and applies it later.
This does not notify observers immediately from that background thread. Instead, the update is queued for delivery on the main thread.
That makes postValue() safe for work coming from background callbacks, repository threads, or legacy async code that is not already on the UI thread.
The Most Important Subtlety: postValue() Can Coalesce Updates
Many developers stop at the thread rule and miss the more important behavioral difference. Multiple postValue() calls made before the main thread processes them may collapse so that observers see only the latest value.
Depending on timing, observers may receive only 3.
That is usually fine when the LiveData represents state, because the newest state is what matters. It is not fine when each intermediate value is meaningful and must be delivered separately.
In other words, postValue() is good for latest-state updates, not for guaranteed delivery of every transient event.
Think in Terms of State Versus Events
If your LiveData represents state such as:
- current loading flag
- latest user profile
- most recent progress percentage
then postValue() is usually acceptable.
If it represents events such as:
- show a toast for every message
- navigate once per action
- append every log line to the UI
then relying on postValue() can be misleading, because intermediate values may be overwritten before observers see them.
That is not a bug in LiveData. It is a mismatch between the data model and the semantics of the update mechanism.
A Practical Rule of Thumb
Use this mental model:
- '
setValue()when you are already on the main thread and want an immediate state update' - '
postValue()when you are off the main thread and want the latest value marshaled safely to the main thread'
Example inside a ViewModel:
In Kotlin, assigning to value is the same idea as calling setValue().
Common Pitfalls
The most common mistake is thinking the difference is only "main thread versus background thread." The coalescing behavior of postValue() matters just as much.
Another mistake is using postValue() for event streams where every individual update matters.
A third issue is calling setValue() from background code and then being surprised by threading problems.
Finally, if your architecture is built around streams of changing state, consider whether StateFlow or SharedFlow is a better fit in new code. LiveData still works, but it is not the only tool anymore.
Summary
- '
setValue()updatesMutableLiveDataimmediately on the main thread.' - '
postValue()schedules a main-thread update and can be called from background threads.' - Multiple pending
postValue()calls may collapse to the latest value. - Use
setValue()for immediate UI-thread state changes. - Use
postValue()for background-thread state updates, especially when only the newest value matters. - Do not model guaranteed one-by-one events as if they were ordinary latest-state updates.

