Android Architecture Components: ViewModel

This post was published in AndroidDev Digest #172 issue

Hi! 👋 Welcome back after a break! Today I’d like to describe ViewModel from Android Architecture Components. As you may know, this component is very useful when you want to provide and manage data for your UI (e.g. Activity or Fragment). Let’s see how to implement ViewModel in your project!

Introduction

Let’s assume you have some Activity. Probably you’ll also have some class to store and provide data for UI (like Presenter known from MVP or ViewModel from MVVM). Unfortunately, user can rotate its phone ಠ_ಠ

What will happen then? Your Activity will be recreated. And there’ll be also your UI data holder. What does it mean to you?

  • you need to remember about passing data to the recreated activity, otherwise, you’ll need to restore it once again (so you’ll make e.g. the second call to database or API)
  • you must be aware of memory leaks that may cause your UI data holder to live longer than activity (and you don’t want that!)

What’s the solution for all those problems? Of course a ViewModel 👍

ViewModel

ViewModel stores your data for UI and it’s lifecycle-aware. What does it mean? Let’s look at this gif:

ViewModel vs simple UI data holder

ViewModel is able to live through the configuration changes. It means that even after the activity is destroyed and recreated after phone rotation, you’ll have still the same ViewModel with the same data. Thanks to this:

  • you don’t need to worry about UI data holder lifecycle. ViewModel will be created automatically by a factory and you don’t need to handle creating it and destroying on your own
  • data will be always updated — you’ll get the same data after phone rotation as it was before. Thanks to this you don’t need to pass manually data to the new activity or make a second call to the database. It’s all done for you!
  • data will wait for you. If you’ll make an API call, you’ll rotate the phone and the result will be delivered before activity will be recreated, you’re sure the data will be stored in ViewModel and you can get it immediately after activity recreation

How to use ViewModel?

To use ViewModel, we need to firstly 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"

From now on, using ViewModel is very simple. Let’s look at the example:

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
}
}

Here we have some data for UI. In this case, it’s a list of users, which we load somehow from the external source. To have ViewModel, we just need to simply extend ViewModel class. And that’s it! Now we’re able to get our UsersViewModel class in the activity:

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);

showUsers(usersViewModel.getUserList());
}
}

To get our ViewModel we use ViewModelProviders.of(). That’s the factory for ViewModels and thanks to this we don’t need to worry about ViewModel’s lifecycle. After getting UsersViewModel we can get some data from it using usersViewModel.getUserList() method. Voilà!

ViewModel vs onSaveInstanceState()

You may ask a question: what about onSaveInstanceState() usually used to store data upon configuration changes? The answer is simple: ViewModel does not replace onSaveInstanceState()!

ViewModel is stored only for activity that is recreated due to orientation changes. In addition to this, onSaveInstanceState() can survive through activity being killed by a system (e.g. when the app goes to the background and system decides to free some memory). What’s the purpose of having them both then? Of course, we could use only onSaveInstanceState(), unfortunately it has few disadvantages:

  • in onSaveInstanceState() we can store only the small amount of data
  • data needs to be Parcelable, so it’s not so easy to set and restore values
  • use ViewModel to store actual data for UI (e.g. list of friends for the user)
  • use onSaveInstanceState() to store data necessary for getting data for activity after it’s killed by the system (e.g. id of the current user)

Thanks to this we’ll have both cases handled. If our activity will be killed by a system, we’ll be able to retrieve a list of user’s friends, because we have an id of the user. And when we’ll get the list, we can store it in the ViewModel and use it even after orientation changes.

That’s it! I hope you liked this post. If you did, don’t forget to 👏 !

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