The Text A and Code A are from this article .
I'm very strange why they don't use Code B or Code C to instantiate the user object. I think Code B and Code C are very simple and clear.
BTW, I havn't test Code B and Code C, but I think that they are correct.
Text A
When using LiveData, you might need to calculate values asynchronously. For example, you might want to retrieve a user's preferences and serve them to your UI. In these cases, you can use the liveData builder function to call a suspend function, serving the result as a LiveData object. In the example below, loadUser() is a suspend function declared elsewhere. Use the liveData builder function to call loadUser() asynchronously, and then use emit() to emit the result
Code A
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
Code B
val user: LiveData<User> = MutableLiveData<User>(database.loadUser())
Code C
val user = MutableLiveData<User>(database.loadUser())
When you're using your B or C approaches to this code, you are calling the MutableLiveData()
constructor, which is a plain old constructor call, meaning that it is executed synchronously, in a blocking way. When you're passing in a call to it, such as database.loadUser()
, that expression will first be evaluated (again, blocking and synchronous, on the same thread), and then its result is passed to the constructor.
The issue with this is that if you're on the main thread for the entirety of the constructor call and whatever you're passing into it, you are blocking that entire thread for the duration of loading the data.
Coroutines allow you to let go of the current thread, by using suspending functions. You can't just mix and match blocking and suspending functions though, as that wouldn't make sense. Instead, you have to call suspending functions inside coroutines.
The liveData
builder function lets you create a LiveData
instance, and feed it data using coroutines, asynchronously, with the ability to call suspending functions, such as loadUser()
in the example, which can be a suspending function. So creating this LiveData
will be quick and non-blocking, while the coroutine you define in that builder can execute asynchronously, and set the result in the LiveData
using emit()
when it's done loading it.