You built a beautiful app, tested it and you thought that your app was ready to use… But what if your users consistently find themselves at places with spotty Internet connectivity?

Don’t underestimate users’ expectations, they are expecting the apps to be fast and responsive. Google states that 29% of smartphone users will immediately navigate away from any app that doesn’t satisfy them. 70% of these cite slow loading.

One way to improve user’s experience is to cache the data. You can use in-memory cache but the data will be lost when the app is killed (either by user or by the OS). You could simply fix this by persisting the web requests, but it creates new problems. What happens if the same data shows up from another type of request? Then your app will possibly show inconsistent data, which is a confusing user experience at best.

In this document I am going to use Android Architecture Components (AAC) with Room to solve this problem. If you are not familiar with AAC, I highly recommend you take some time before continuing to read through the “Applying Android Architecture Components with Kotlin”

Room

Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

Apps that handle non-trivial amounts of structured data can benefit greatly from persisting that data locally. The most common use case is to cache relevant pieces of data. That way, when the device cannot access the network, the user can still browse that content while they are offline. Any user-initiated content changes are then synced to the server after the device is back online.

The core framework provides built-in support for working with raw SQL content. Although these APIs are powerful, they are fairly low-level and require a great deal of time and effort to use:

There is no compile-time verification of raw SQL queries. As your data graph changes, you need to update the affected SQL queries manually. This process can be time consuming and error prone.

You need to use lots of boilerplate code to convert between SQL queries and Java data objects.

Room takes care of these concerns for you while providing an abstraction layer over SQLite.

There are 3 major components in Room:

1. Database: You can use this component to create a database holder. The annotation defines the list of entities, and the class’s content defines the list of data access objects (DAOs) in the database. It is also the main access point for the underlying connection. The annotated class should be an abstract class that extends RoomDatabase.

2. Entity: This component represents a class that holds a database row. For each entity, a database table is created to hold the items.

3. DAO: This component represents a class or interface as a Data Access Object (DAO). DAOs are the main component of Room and are responsible for defining the methods that access the database. The class that is annotated with @Database must contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao. When generating the code at compile time, Room creates an implementation of this class.

Let’s get our hands dirty with some coding.

Demo App: GitHub List.

https://github.com/BakhtarSobat/GitHubList

In the first version of the app, we will use a simple version of implementation in the next part we will look at implementation using the NetworkBoundResource class.

Our demo app is very simple, it only shows Jake Wharton Github repositories as list.

As it is mentioned before, the app architecture is based on my previous document, internally it looks like this:

We extend the repository functionality by adding a new datasource which will cache the data.

We use the Room persistence library for our caching. Let’s start defining our Database, Entity and DAO.

Entity component: This component represents a class that holds a database row. For each entity, a database table is created to hold the items.

Database component: This component is responsible for creating a database holder. The annotation defines the list of entities, and the class’s content defines the list of data access objects (DAOs) in the database.

DAO component: This component represents a class or interface as a Data Access Object (DAO). DAOs are the main component of Room and are responsible for defining the methods that access the database.

The DAO will be injected to our repository, using Dagger2. The repository contains 2 methods:

1. Returning the result

2. Refreshing the result

The first method creates the mediator, observes the database changes, calls the refresh method and returns the mediator LiveData. The refresh method, which runs in a workerthread, retrieves the data from the webserver and updates the database. Room knows when the database is modified and it will automatically notify all active observers when the data changes. Because it is using LiveData, this will be efficient because it will update the data only if there is at least one active observer. Since the mediator observes the result of the database, it will get triggered, which in turn will be observed by the caller of the function.

The refresh method checks if there is a need to update the data, retrieves the data and updates the database. Nothing special.

Conclusion

Once the data is stored, the app can be used even when there is no connection. In this model, the database serves as the single source of truth, and other parts of the app access it via the repository. Since Room returns a LiveData, we can observe it and Room will notify us when the data changes.

Please notice, in this part we omitted network error and loading states to keep the demo app simple. In the next part we will extend our demo app by making use of NetworkBoundResource class to demonstrate a way to expose network status. part 2.

Find the source code @ https://github.com/BakhtarSobat/GitHubList