Repository Pattern in Android

Ezra Lazuardy
The Startup
Published in
7 min readAug 1, 2020

--

In-depth guide about the implementation of repository pattern in Android MVVM architecture.

We know that the application of MVVM architecture pattern in Android app project will really help in building clean and structured code. The main reason is MVVM can separate component based on their respective duties.

In short, MVVM have 3 main component called Model — View — View Model. View component will show data and manage the user interactions, View Model will handle all request and provide all data needed for View, and Model will storing data and handle the business logic.

Source: Wikipedia

But the problem is, even if you have implemented this architectural pattern correctly, some code duplication may still appear, especially when you need to accessing data from local or remote database. For instance, you need to fetch data from remote database using Retrofit. More or less, you’ll need these code below to be implemented in your View Model.

val book = liveData {
val bookDAO = Retrofit.getClient().create(BookDAO::class.java)
val book = bookDAO.getBook()
emit(book)
}

Put in a simple scenario, this book Live Data variable will later be observed in the View. But, you may notice that the Retrofit boilerplate codes are required to setup the DAO if you need to access some resource from remote database.

This is the problem that we want to be fixed for, in order to simplify the need of accessing data and centralize the data access in our MVVM architectural pattern.

Single Source of Truth

Photo by Silviu Beniamin Tofan on Unsplash

In order to centralize the data access, we need something called Single Source of Truth (SSOT).

In information systems design and theory, single source of truth (SSOT) is the practice of structuring information models and associated data schema such that every data element is mastered (or edited) in only one place.

It is basically a practice to centralize your data access into a single class (based on the usage of the data). For instance, you need to access the data about book, then you have to centralize all the data access which related to book into a single class so that the other class (client) can easily fetch the book data by requesting to “source of truth” class.

And because all other locations of the data access just refer back to the primary “source of truth” location, updates to the data element in the primary location propagate to the entire system without the possibility of a duplicate value somewhere being forgotten.

Deployment of a SSOT is becoming increasingly important in enterprise settings where incorrectly linked duplicate or de-normalized data elements (a direct consequence of intentional or unintentional denormalization of any explicit data model) pose a risk for retrieval of outdated, and therefore incorrect, information.

A common example would be the electronic health record, where it is imperative to accurately validate patient identity against a single referential repository, which serves as the SSOT.

The Repository Pattern

Photo by Jaredd Craig on Unsplash

To apply the SSOT practice in our app, we need to implement the repository pattern. Repository pattern is one of the design patterns that available out there. For those who don’t know about design patterns, it’s are used as a solution to recurring problems in your applications, and the repository pattern is one of the most widely used design patterns.

Repository pattern will persist your objects and the need of having to know how those objects would be actually persisted in the underlying database, i.e., without having to be bothered about how the data persistence happens underneath. The knowledge of this persistence, i.e., the persistence logic, is encapsulated inside a class called “Repository”.

Repository pattern implements separation of concerns by abstracting the data persistence logic in your applications

In essence, the Repository design pattern facilitates de-coupling of the business logic and the data access layers in your application with the former not having to have any knowledge on how data persistence would actually take place.

“Repository will mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.” — Martin Fowler

In using the Repository design pattern, you can hide the details of how the data is eventually stored or retrieved to and from the data store. This data store can be a database, an xml file, etc. You can apply this design pattern to even hide how data that is exposed by a web service or an ORM is accessed.

“Use a Repository to separate the logic that retrieves the data and maps it to the entity model from the business logic that acts on the model. The business logic should be agnostic to the type of data that comprises the data source layer. For example, the data source layer can be a database, a SharePoint list, or a Web service.” — MSDN

A Repository is defined as a collection of domain objects that reside in the memory.

Implementing in Android

If you read the Android documentation about recommended app architecture, you may notice that Google also recommend you to use repository pattern alongside with the famous MVVM architectural pattern.

Source: Android Developer Docs

Notice that each component depends only on the component one level below it. For example, activities and fragments depend only on a view model. The repository is the only class that depends on multiple other classes; in this example, the repository depends on a persistent data model and a remote backend data source.

This design creates a consistent and pleasant user experience. Regardless of whether the user comes back to the app several minutes after they’ve last closed it or several days later, they instantly see a user’s information that the app persists locally. If this data is stale, the app’s repository module starts updating the data in the background.

Ok, enough theory. Let’s try to implement the repository pattern in Android.

First thing first, let’s prepare the DAO (Data Access Object) for REST API path mapping that used by Retrofit.

interface BookDAO {

@GET("/book/latest")
suspend fun getLatestBook(): Book
@GET("/book/all")
suspend fun getAllBooks(): List<Book>
}

Second, create the DAO instance using the Retrofit builder.

@Module
@InstallIn(ApplicationComponent::class)
object RemoteDatabase {

@Provides
@Singleton
fun provideBookDAO(): BookDAO =
Retrofit.getClient().create(BookDAO::class.java)
}

Notice that I use the Dagger Hilt for dependency injection purpose. I hope you have basic knowledge about it, because I’m not explaining how it works and how it should be coded in this article 😉.

Third, create the Repository class to centralize the data access.

@Module
@InstallIn(ActivityRetainedComponent::class)
class BookRepository @Inject constructor(
private val bookDAO: BookDAO
) {
suspend fun getLatestBook() = bookDAO.getLatestBook() suspend fun getAllBooks() = bookDAO.getAllBooks()
}

Notice that I use the ActivityRetainedComponent type for InstallIn Dagger Hilt annotation. This component type is required since the repository class will be used by View Model that has the lifetime of a configuration surviving activity.

This repository class may use many DAO that needed to centralize the data access (based on it’s usage).

Now, the last thing to do is to apply the Repository to the View Model class that need it.

class BookViewModel @ViewModelInject constructor(
private val bookRepository: BookRepository
) : ViewModel() {
val latestBook = liveData {
emit(bookRepository.getLastestBook())
}
val allBooks = liveData {
emit(bookRepository.getAllBooks())
}
}

View Model can also use several repository class that needed to satisfy data needed in View. Now, the View that use the BookViewModel can easily get the data from BookRepository by observing it’s Live Data.

Conclusion

Implementing repository pattern will create a data access layer that can give us pain-less data access. Not only that, by using this design pattern will help us to centralize all the data access that cause reduced boilerplate and duplicated code in the app.

You can clone the example project of repository pattern implementation in Android (with Dagger Hilt) here:

--

--

Ezra Lazuardy
The Startup

“An idiot admires complexity. A genius admires simplicity.” — Terry A Davis