Android Architecture Components — Room, LiveData and ViewModel

During the concluded Google I/O 2017, there were some amazing announcements about Android. Say hello to Android Architecture Components. For once, these are announcements that ease our lives as Android Developers.

Android Architecture Components

A new collection of libraries that help you design robust, testable, and maintainable apps. — developer.android.com

It helps us developers address two pain points:

  1. Manage our UI components lifecycle
  2. Persist data over configuration changes

In fact, these are the two biggest problems we Android Developers face. Period.

Maintaining data over orientation changes and handling our objects with lifecycle is hard. That’s why, to avoid the hassle, you lock your apps in Portrait mode, don’t you? Don’t lie. Even I’ve done it.

But don’t worry, Android Architecture Components will help alleviate both our fears.

We will see 3 main components :

  1. Room
  2. ViewModel
  3. LiveData

So first, let’s find out what these components actually are. Then, we’ll learn how we can use them.

We’ll even make a handy app that keeps track of what people borrow. This will help us learn better about how all these 3 components work together.

Room

Remember the amount of boilerplate code you had to write to create and manipulate even a very small database? You had to define the database structure, create an SQLiteHelper class etc.

Room is a library that saves you all such trouble. Now you can query your data without having to deal with cursors or loaders. You can define your database by adding annotations in your Model class. Yes, it’s that simple.

If you’ve used third-party ORMs like Sugar, you’ll feel right at home here. In fact, from now on, I wouldn’t even want to use one. Room is that brilliant! Why would you want to use a third-party library, when the official Android libraries give you an equal, or if not, better solution.

Architecture

In this app, we will follow an architecture called MVVM — Model View ViewModel.

In MVVM, the ViewModel exposes the required data and interested parties can listen to it.

But you don’t have to worry. We’ll do a simple implementation for this article. You’ll have no problem following.

So in our case, the Activity will listen on the data and make changes in the UI.

Getting started

Create a new project in Android Studio.

First, Add Google’s maven repository to your project-level build.gradle file.

Next, add the following dependencies for Architecture Components and Room in your app-level build.gradle file.

Creating the Model

We will call our model BorrowModel.

You might see an error at DateConverter.class. But don’t panic, we’ll create that next. So for now, pay attention to the Annotations used here.

We use the @Entity annotation to tell Room to use the current class as a database table.

Any attribute preceded by the @PrimaryKey annotation will serve as a primary key for the table. Here we use 'autoGenerate = true' so that the key is automatically generated every time an entry is made.

SQL cannot store data types like Date by default. That’s why we need a way to convert it into a compatible data type to store it in the database. We use the @TypeConverters to specify the converter for the borrowDate attribute. So to help us with this conversion, we’ll create a class called DateConverter.

As you can see, the class just converts Date to Long and vice versa.

Data Access Object

Next up, we need to create a DAO — Data Access Object class. This class will be used to define all the queries we will perform on our database.

We use @Dao to tell Room that this is a DAO class.

We define our queries as strings and pass them as a parameter to @Query. Each @Query annotation is paired with a method. When the paired method is called, the query gets executed.

Next, we use the @Insert annotation for methods that insert entries into the table. We can similarly use @Delete and @Update for deletion and update method respectively.

In case there are conflicts during such manipulation operations, we have to specify a conflict strategy too. In our example, we are using REPLACE. It means that the conflicting entry will be replaced by the current entry.

Make sure you import REPLACE correctly using import static android.arch.persistence.room.OnConflictStrategy.REPLACE;

Creating the database

Now, all we need to do is create a RoomDatabase class. So create an abstract class called AppDatabase.

We annotate the class with @Database which takes two arguments:

  1. An array of the Entity classes(the tables)
  2. The database version which is just an integer.

This class is used to create the database and get an instance of it. We create the database using

Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "borrow_db")
.build();

The arguments are:

  1. Context
  2. Your database class
  3. Name to given to the database

TIP:
We have to create an abstract method for every DAO class that we create. This is really important.

And that’s it. Our database is ready to roll.

ViewModel

Earlier in the post, we mentioned ViewModel. ViewModels are entities that are free of the Activity/Fragment lifecycle. For example, they can retain their state/data even during an orientation change.

ViewModels do not contain code related to the UI. This helps in the decoupling of our app components.

In Room, the database instance should ideally be contained in a ViewModel rather than on the Activity/Fragment.

Create the AndroidViewModel

We create a ViewModel for our borrowed items.

Every ViewModel class must extend the ViewModel class. If your ViewModel needs the application context, it must extend AndroidViewModel. The ViewModel will contain all the data needed for our Activity. In our example, we are using something called LiveData.

LiveData is a wrapper that lets interested classes observe changes in the data inside the wrapper.

We wrap our list of borrowed items inside LiveData so that the Activity can observe changes in the data and update the UI.

In our ViewModel, we first get an instance of our database using AppDatabase.getDatabase(this.getApplication())

First, we need to load the list of borrowed items from the database. For that, we should use the query we defined in the DAO class, getAllBorrowedItems().

Next, call the abstract method we created for DAO and then call the query method. Refer to this snippet in the BorrowedListViewModel class.

appDatabase.itemAndPersonModel().getAllBorrowedItems();

Now since we will be displaying a list of items, we need a RecyclerView. So first, let’s create an adapter for the same.

Creating the Android LifecycleActivity

It’s a pretty straightforward adapter. So I won’t be getting into the details of it. But if you’re interested in how RecyclerView works, this Android tutorial tells you how to create a RecyclerView.Adapter.

Now create an Activity that extends LifecycleActivity to display a list of all the borrowed items.

LifecycleActivity is a class that provides us with the state of the lifecycle.

EDIT: We no longer need to extend LifecycleActivity explicitly. The required methods are available in AppCompatActivity.

NOTE:
Whenever we need to use ViewModels inside our Activity, the Activity must extend LifecycleActivity.

Creating a ViewModel is simple.

viewModel = ViewModelProviders.of(this).get(BorrowedListViewModel.class);

The two parameters are:

  1. Context
  2. The ViewModel class

Now we need to make our Activity observe the changes in the ViewModel. So first, get a reference to the LiveData inside the ViewModel. Then, add an observe() method to the reference.

The observe() method takes 2 parameters:

  1. The owner of the Lifecycle. In our case, it is the Activity.
  2. An Observer.

Whenever there is a change in the data, the onChanged() callback is executed and we get the new data. We can update the UI accordingly.

Simple Exercise — Create the ‘Add Item Screen’

Now we have an Activity that can display a list of borrowed items. But how do we add items to the database?

It’s simple. You need to create an AddItemActivity.

The entire procedure is exactly the same as before. But in this case, you need to call the addBorrow() DAO method and pass a Borrow object as a parameter. And that is it. Our app is ready.

I encourage you to try this screen on your own. But in case you get stuck, you can refer to my files on GitHub.

Output

So go ahead and run your app. You should get an output similar to this.

The Android Architecture Components give us great advantage and relief. Hence, we don’t have to worry about

  • lifecycle changes
  • memory leaks
  • data retention across configuration changes

If you recount, these are the biggest challenges faced by even veteran Android developers.

Source Code:
As always, the code from the post can be found on GitHub.

Wrap up

In the post, we got introduced to Android Architecture Components. Then, we learnt about Room and used it to create databases in a fast and easy way. Next, we also learnt how to make our UI respond to changes in data. Also, by using LiveData and ViewModels, we did not have to use a lot of callbacks.

Additionally, we even learnt a bit about the MVVM architecture.

We have barely scratched the surface in terms of what’s possible with these new components. So I hope to discover more as I continue to tinker with Android Architecture Components.

So are you going to use these components? Would you consider Room in any of your apps? Or maybe ViewModels to simplify your code? I’d love to hear your comments.

Special shout out to Suleiman Ali Shakir for always helping me out and making amazing edits and Raghav Sai for correcting the endless derps.gi

First published at blog.iamsuleiman.com on May 23, 2017.

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