LiveData: postValue() vs setValue()

Google introduced LiveData as a component in its Android architecture component. In a brief description LiveData is:

LiveData is an observable data class. Unlike a regular observable, LiveData is life-cycle aware.

Let take a look at the documentation:

This class is designed to hold individual data fields of ViewModel, but can also be used for sharing data between different modules in your application in a decoupled fashion.

It means that we are able to use LiveData to allow call service to control the UI in the corresponding activity. In practice we place MutableLiveData object inside the Service class, and exposes it to the ServiceBinder, where the activity will obtain the immutable version of it.

Then when we want to update the UI, just simply push new values to the MutableLiveData from the Service and the Activity should respond correspondingly. Or? Let take a look at a basic sample:


class LiveDataActivityTest : AppCompatActivity(), View.OnClickListener {
    private lateinit var livedataService: LiveDataServiceTest
    private lateinit var data: LiveData
    private var isBound: Boolean = false

    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            val binder = service as LiveDataServiceTest.ServiceBinder
            livedataService = binder.getService()
            data = binder.getData()
            isBound = true
            Timber.d("Service connected.")

            data.observe(this@LiveDataActivityTest, Observer {
                it?.let { value ->
                    Timber.d("received progress: $value")                                      
                    ObjectAnimator.ofInt(progressBar, "progress", value * 10).start()

        override fun onServiceDisconnected(name: ComponentName?) {
            isBound = false
            Timber.d("Service disconnected.")

    override fun onCreate(savedInstanceState: Bundle?) {

        val intent = Intent(this,
        bindService(intent, connection, Context.BIND_AUTO_CREATE)


    override fun onClick(p: View?) {
        if (isBound) {


class LiveDataServiceTest : Service() {
    private val binder = ServiceBinder()
    private val data = MutableLiveData()

    inner class ServiceBinder : Binder() {
        fun getService(): LiveDataServiceTest = this@LiveDataServiceTest
        fun getData(): LiveData =

    override fun onBind(intent: Intent?): IBinder = binder
    fun updateProgress() {
        for (i in 1..10) {
            Timber.d("post progress: $i")

It is not our expectation because the progress is updated incorrectly.

post progress: 1
post progress: 2
post progress: 10
received progress: 10

Two ways of mutating values:

If we take a look at the source code of LiveData, we can see two methods: postsValue() and setValue(), which are both protected. The only different of MutableLiveData is that it exposes these two methods, allowing users to mutate values inside.

From the method name we can infer something: postValue() will probably take effect later, while setValue() will update the value directly. This is documented as well. setValue() is straightforward, so let’s look at postValue().

  • The documentation mentions that if we all setValue() right after postValue(), the value will be set first and will later be overridden by the value in postValue(). This verifies our assumption earlier.
  • The last sentence contains more information:
    • If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched

If we call postValue multiple times, possibly in different methods, and the post values is not executed yet, the value will be dispatched once only.

This was actually different to my own assumption previously. I thought that if I post different values, even though the later values will override the earlier ones, the earlier ones should still be dispatched. But Android use a different approach here. Let’s look at the source code:

private static final Object NOT_SET = new Object();

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    if (!postTask) {

private final Runnable mPostValueRunnable = new Runnable() {
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        //noinspection unchecked
        setValue((T) newValue);

So we have synchronized here, the reading and writing operation of mPendingData are both locked so that at most one thread can access it.
The NOT_SET value declared as a static variable, to be used to check whether user has posted value to be updated later. Whenever we call postValue(), the internal mPendingData will be updated, but the task will not be posted twice, since mPendingData was not NOT_SET.

The Runnable is the one posted to the main thread. It simply takes the current value of mPendingData, and resetting it to NOT_SET.

The code is simple, and we don’t see any queueing or replay operations here. LiveData only keep the latest value posted, and updates it when main thread is available.

We think that the reason behind this is that: Android assumes that the data we posted is stateless, and no order should be guaranteed between multiple values (posted in a short time). Based on this assumption, it will only fire one task to update the UI, in order to keep the resource usage low.

Now changing the update value method in service to setValue()

post progress: 1
received progress: 1
post progress: 2
received progress: 2
post progress: 10
received progress: 10


In voice call feature, we need to update the UI frequently, and the data behind UI is definitely stateful: e.g., Calling (the phone shall ring), Connecting, Connected (shall display the call duration), Disconnected, Closed (shall close the activity). And most of the time data comes from different sources: from WebRTC and from the Server.

LiveData seems not to be the best choice, if we do want every change to be displayed on the screen, and order should be maintained. But compared to sending intents around and writing a lot of boilerplate code to register actions?

Therefore since we are still using it, we need to figure out a way to make sure our UI is updated correctly: use setvalue(). As documented, setValue is guaranteed to dispatch values, although it might be overridden later. What we did in practice is that, if we can confirm we are in the main thread, we set the value directly instead of posting it again. Otherwise, we post the value via postValue().

If you have any idea regarding to the usage of LiveData, please share and I’m really happy to discuss about it!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s