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:

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:

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.

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!

In Java, whenever you want to wrap some actions and execute them later, we will probably use Runnable implementation. The run() method of the Runnable interface takes in no parameters and returns nothing. Many methods will take in Runnable as a callback or as a way to execute actions later.

In Kotlin, the more idiomatic way is to use an anonymous function, i.e, a lambda expression. In this case the run() is () -> Unit. If you forgot the syntax, it has the same semantic as { print("Hello world") }

But not for their usages

Kotlin is designed to simplify code writing, they make it simpler by calling methods that take in a SAM (Single Abstract Method). For example, the Android Handler class has post() method, which requires a Runnable, so in Kotlin, you can simply write:

val handler = Handler()
handler.post {
Log.d(TAG, "action")
}﻿

Suppose now you want to remove the runnable, you may want to call the removeCallbacks() method, like this:

handler.removeCallbacks {
Log.d(TAG, "action")
}﻿

Well, this is NOT going to work. To remove callbacks, Handler actually compares the references of the Runnable objects, and only the same reference that we passed into the post() method will be removed. In this case, two lambda expressions actually create two different objects. Although their contents are exactly the same, the posted Runnable will still be run.

Take a look at the decompiled bytecode (as in Tools -> Kotlin -> Show Kotlin Bytecode):