AndroidPub
Published in

AndroidPub

Android Architecture Components: LiveData

Hi! Welcome to the next article from the series about Android Architecture Components!

Lately, we discussed ViewModel useful for providing and maintaining data for your UI component as Activity or Fragment. If you didn’t read this, I encourage you to do it. Today we’ll talk about LiveData, which is a lifecycle-aware observable data holder. Let’s start!

Introduction

We’ll reuse example from the previous post about ViewModel, where we had some ViewModel class with the list of users inside:

public class UsersViewModel extends ViewModel {

private List<User> userList;

public List<User> getUserList() {
if (userList == null) {
usersList = loadUsers();
}
return userList;
}

private List<User> loadUsers() {
// do something to load users
}
}

Thanks to the ViewModel we don’t need to worry about many things, e.g. passing data to the recreated activity after configuration changes or memory leaks caused by ViewModel living longer than Activity.

But what if instead of getting the data every time we need it, we’ll be simply… notified every time there’s something new? Sounds familiar?

It’s possible thanks to LiveData, which is a lifecycle-aware data holder with the observer pattern! Let’s see what does it mean to you.

How does it work?

When we have a LiveData object (e.g. list of users), we can add some LifecycleOwner (it can be Activity or Fragment) as an observer to this data updates. Exactly as in the observer pattern, but with respecting lifecycle states. Thanks to this:

  • we (as an Activity or Fragment) we’ll be notified every time the data changes instead of requesting the data each time from ViewModel (so the UI is always updated!)
  • it’s all bounded with lifecycle, so we’ll be registered for observing those changes only if Activity (or any other LifecycleOwner) is in STARTED or RESUMED state and only then LiveData will emit any items (so no more memory leaks and NullPointerExceptions due to unexisting view!)

How to use it?

Firstly, we need to add proper dependencies into our app/build.gradle file:

implementation "android.arch.lifecycle:extensions:1.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"

Now let’s use a LiveData with the list of users from a previous example:

public class UsersViewModel extends ViewModel {    private MutableLiveData<List<User>> userLiveData = 
new MutableLiveData<>();
public UsersViewModel() {
setUserListRefreshCallback(newUserList -> {
userLiveData.postValue(newUserList);
});
}

public LiveData<List<User>> getUserList() {
return userLiveData;
}
}

Firstly, we wrap List<User> with MutableLiveData. We’d like to change LiveData only inside UsersViewModel class and that’s why there’s a mutable version of LiveData.

Every time there’s some change in the data (e.g. from some external source), we’d like to post a new value to LiveData. We can do it using methods as postValue() (asynchronously) or setValue() (synchronously, so we need to do it on the UI thread on our own).

Later, we can expose LiveData with a getter, so the Activity can use it easily:

public class UsersActivity extends AppCompatActivity {

@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

UsersViewModel usersViewModel =
ViewModelProviders.of(this).get(UsersViewModel.class);

usersViewModel.getUserList()
.observe(this, this::showUsers);
}
}

We see the difference in getting the data — now we’re adding ourselves as an observer to the user list changes. We pass to the observe() method two parameters — first one is LifecycleOwner (so basically our Activity) and thanks to this LiveData knows when it should notify Activity about changes. The second one is a callback with List<User> parameter, which we can use in showUsers() method.

From now on, we don’t need to worry about handling lifecycle states and registering/unregistering from this observable!

Doing more with LiveData

We can play a little with LiveData thanks to the Architecture Components classes. For example, if we’d like to make some changes on the LiveData before exposing it from ViewModel, we can do it by using Transformations:

Transformations.map()

If we don’t need the whole User objects, but only their names, we can use map() function:

LiveData<String> userNames = Transformations
.map(userLiveData, user -> {user.name});

MediatorLiveData

We can also merge multiple LiveData observables into one source by using MediatorLiveData. For example, if we’d like to merge data from the database and the network we can do it this way:

LiveData<List<User>> usersFromDatabase;
LiveData<List<User>> usersFromNetwork;

MediatorLiveData<List<User>> usersLiveData =
new MediatorLiveData<>();
usersLiveData.addSource(usersFromDatabase, newUserList ->
usersLiveData.setValue(value));
usersLiveData.addSource(usersFromNetwork, newUserList ->
usersLiveData.setValue(value));

Thanks to this Activity can observe only usersLiveData object and will be notified every time there’s a change in any of these.

LiveData & Room

If you use Room in your project (and if you don’t — why?) you should know that your queries can return LiveData objects:

@Dao
public interface UserDao {
@Query("SELECT * FROM users WHERE name=:name")
LiveData<List<User>> getUsersByName(String name);
}

Thanks to this, queries will be made asynchronously (so you don’t need to worry about making them on a proper thread) and you’ll have the observer pattern for free (so every time the content in the database will change, you’ll be notified about this!)

--

--

--

The (retired) Pub(lication) for Android & Tech, focused on Development

Recommended from Medium

Biweekly update #8

Functional Programming Unit Testing in Node — Part 5: Noops, Stub Soup, and Mountebank

Reaching the Azure Clouds by building an Airplane and Flying it

Public methods in ruby (part 1/2)

Trends in Serverless Computing in 2021

Shell Scripting Crash Course

Post Covid Hack Live Broadcast Recap

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Paulina Szklarska

Paulina Szklarska

Flutter GDE / Flutter & Android Developer / blogger / speaker / cat owner / travel enthusiast

More from Medium

How to pass params on App Switch from Cordova to KOTLIN App

How to Use Upserting in Room

Dynamic Android Resources using Bash Scripting

MVP Implementation in Android with Kotlin