Implementing Single Source of Truth in Android

Jephthah Afolayan
4 min readJul 5, 2023

--

Single-source of truth (SSOT) architecture is a software engineering principle that also applies to Android app development. It is defined as, and quoted,

the practice of structuring information models and associated data schemas such that every data element is mastered in only one place, providing data normalization to a canonical form.
- Wikipedia

This article seeks to explain this architecture in relation to Android app development, as well as implement a sample project illustrating this concept.

Why do we need SSOT?

With Android, the primary source of truth is mostly the local database. This local database is usually implemented using Room, SQLite, RealmDB, etc. This approach to architecting an Android app is beneficial because it keeps data in one place, and only the item's reference is passed around in the application. It is also easier to sync and update data from this single source. SSOT ensures data integrity, which refers to data’s overall accuracy, completeness, and consistency. Keeping data in a primary source of truth location ensures that the saved data is consistent and accurate across the app.

Any Android app that provides offline-first functionality needs to ensure the data is kept and made easily accessible. A use case class can be exposed such that any screen interested in accessing the data can have access without much work. If a single object is needed, the identifier for an object can be used as a reference for this object.

The flow chart below illustrates this concept.

A simple flow chart illustrating the single source of truth principle in android

Project setup

The project uses the MVVM architectural pattern alongside Room and Flows. It fetches random quotes from an API using Retrofit and saves the quotes in the Room DB. This setup is fairly easy to implement and ensures the extendability of the project, meaning new features can be added, using the same repository, without much overhead.

On Android Studio, create a new project then add the following dependencies.

// okhttp & retrofit
implementation “com.squareup.okhttp3:okhttp:4.10.0”
implementation “com.squareup.retrofit2:retrofit:2.9.0”
implementation “com.squareup.okhttp3:logging-interceptor:4.9.1”
implementation “com.squareup.retrofit2:converter-gson:2.9.0”
// hilt
implementation “com.google.dagger:hilt-android:2.42”
implementation ‘androidx.hilt:hilt-navigation-compose:1.0.0’
kapt “com.google.dagger:hilt-compiler:2.42”
// room db
implementation “androidx.room:room-ktx:2.6.0-alpha02”
implementation “androidx.room:room-runtime:2.6.0-alpha02”
kapt “androidx.room:room-compiler:2.6.0-alpha02”
  • OKHttp and Retrofit for fetching data from the remote API.
  • Hilt is added for dependency injection.
  • Room library provides an abstraction layer over SQLite to allow fluent database access

We proceed to set up the data source classes. We’ll need the remote and local data source files for this project. The remote data source would manage how we fetch data from the API, and the local data source manages how data is fetched from the local database.

Database setup

One of the capabilities of the Room database is the support for observable read queries in the DAO (data access object) class. When the state of the database changes, the database can emit new values that meet the queries' condition. These observables can be Flow<T> (Kotlin), Flowable, Observable, Publisher(RxJava), or LiveData. For this project, we’ll use Kotlin Flow. The flow would emit new quotes as soon as they’re fetched from the API, thereby keeping our database as the single source of truth for the quotes. This ensures we do not update the UI directly from the API but from the database.

RandomQuotesDatabase.kt
RandomQuotesDao.kt
The local data source

Remote data source

The API Service and remote data source classes

Repository setup

Repository class

Use cases

Use cases make up the domain layer but would be skipped for this tutorial. It is part of the full project available on GitHub. For the project, we set up two use case classes, one for each of the repository functions.

ViewModel

The ViewModel class is part of the presentation layer, and it brings together all these classes and functions. The important functions of this class are the getRandomQuotes() and fetchRandomQuote() functions. The first sets up a flow of data and listens to changes in the database. fetchRandomQuote() is enabled to allow users to add a random quote to the UI.

Note that the if-check in lines 18–24 can be moved down one layer into the use case class. Keeping it this way makes the use case class definitive and contains only one functionality.

Conclusion

The database of an Android application serves as the source of truth for offline-first applications. This ensures data accuracy and correctness. Also, we’ve been able to demonstrate how to implement the SSOT concept with a sample Android application. The application fetches random quotes from an API resource and saves them on a local database. The UI is then populated with the data from this database.
Do reach out in the comment section in case there’s a need for clarification.

Github repo

References

--

--