New Android architecture components in action: creating a restaurants map application with Room, ViewModel, LiveData and Dagger 2

Part 1: Architecture overview; Room, web server and Repository components.

Roman Tolmachev
AndroidPub

--

Part 2: ViewModel, View and Dagger.
Part 3: Tests

Good design makes separate parts play as a whole. Loftollah mosque in Esfahan, Iran. (From here.)

One of implicit benefits of being a software developer is that you always learn something new. The way you see things (and not only the technical stuff) is constantly changing, and for me this is one of the reasons I still enjoy programming.

This year Google announced a very much needed architecture guide for Android, introducing new architecture components. Needed because as an Android developer you have many ways to achieve the same goal — using ContentProviders + Loaders, or RxJava, or Agera, or event bus etc… following some flavour of MVP or MVVM or pretty much without any formal architecture. Give the same task to 5 different people and you’ll get 5 different designs.

Architecture promoted by Google is the Model — View — ViewModel pattern. It facilitates separation between business logic layer and user interface layer, gluing them together reactively using Observer pattern.

In terms of new Android components this means:

Model is the data access layer, typically a Repository which receives data from different sources, like web server (using Retrofit) or database (using Room), and provides it to whoever is interested;

View is the user interface layer, typically Activity or Fragment, which contains only user interface related code, i.e. how you present the data;

ViewModel lies between View and Model, providing data to View while hiding business logic from it. New ViewModel component was designed to behave well with Activities and Fragments in a sense that it survives configuration changes and keeps the data cached;

Binder that glues it all together is a LiveData component, which is an Observable, smart enough to work effectively with Android Lifecycle-aware components, pushing changes only to active observers.

In other words, it’s a MVVM architecture carefully adjusted to Android realities, where components have different life cycles, and addresses mobile-specific caveats like configuration changes, foreground/background states etc.

In this and following posts we’ll build a sample application using these new components, as well as Dagger 2 for dependency injection, and completely in Kotlin. In the third part, we’ll go through unit, integration and functional testing.

The application will be a map with restaurants, separated by different types of cuisines: Peruvian, Italian and Chilean. Clicking on a marker will open a Fragment with restaurant’s details such as photo, name, price and short description. Selecting cuisine type via Spinner will filter restaurants shown on the map.

All the information used — names, images, descriptions, etc, was taken from popular local website.

To emulate web server, we’ll use a fork of My JSON Server. Take a look at the data returned by that link, since it will define the entity.

Once loaded from the server, data will be stored in the local database and loaded from there next time we need it.

So, in order to implement the desired MVVM architecture, we’ll separate the project into these logical parts:

Repository represents Restaurants data domain, and fetches data from both web server and local database. ViewModel contains Repository object, and View observes it through ViewModel. Data observed will be wrapped into LiveData<>.

Let’s start with the model. Restaurant will have id, cuisine, name, latitude, longitude, price, image and description. Some of these parameters are important so that we won’t accept a restaurant without name, or cuisine type, or valid latitude and longitude. After all, we show them on the map! Other parameters like image or description are optional.

To achieve this, we combine Room annotations with Kotlin. @Entity annotation constructs Room entity object, while Kotlin data keyword provides us with the boilerplate POJO code. val image: String = "" means that we provide default value for optional parameters, while val name: String? explicitly says that it is nullable, and we must check it before passing to DAO.

DAO, or Database Access Object, is also constructed with Room annotations and is straightforward to use.

Finally, we need a database to store the data.

One thing to mention, is the version parameter. Room recommends exporting schemas for each version so that you could make migrations easier later. You can specify the schema folder in the app/build.gradle file following the link above.

Keeping database schemas history facilitates migrations

With database source ready, we can switch to the web server part. I won’t touch on using Retrofit, but rather on using a mock web server. I recommend this post to see the options you have and why you should use mock web server in the first place. I myself use standalone WireMock server in development, since it allows you to test for edge cases, 40x and 50x errors, complex scenarios (via state machine) and whatever you want, really. My environment looks like this:

Wiremock standalone .jar (with .json stubs) sits in a folder in the root directory

Run it via Terminal tab in Android Studio, make changes to .json stubs, restart, make changes, repeat. Very convenient. Since I run app on a device, I needed to figure out my own IP in the shared network and put it in the gradle:

The last thing I would like to mention today is quite tricky. That is, how do you combine both database and web server sources into a Repository? In the architecture guidelines Google shared example of such a way. First, we wrap LiveData around a Resource class which has request status (loading, success or error), data and a error, if any. Then, we use NetworkBoundResource class to merge both sources into a single source of truth, the database. I somewhat simplified it (compared to the original Java class in Addendum) and translated into Kotlin. The resulted RestaurantsRepository also follows Google’s original Java repository class.

Decision tree for my NetworkBoundResource class

The decision tree is a bit different from the original one from Addendum in a sense that it has loading -> success/error flow; original tree has loading -> success -> loading -> success/error flow. I decided to leave it this way for my case.

So far so good, we’ve done the first part. Thank you for your time, and be sure to leave comments below. In the next part we’ll implement ViewModel and View components. Check the whole project at Github:

--

--