Firestore Caching: You may not need Room

Muhammed Esad Cömert
3 min readFeb 27, 2023

--

Best practices, clean architecture, and design patterns, we are used to hearing these words every day. Often in this noise, we can miss straightforward solutions.

In this article, I will talk about something that can save you from;

creating type converters,

writing ugly SQLite queries for migration,

val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"ALTER TABLE database RENAME TO databaseOld;" +
"CREATE TABLE database (" +
"id INTEGER PRIMARY KEY NOT NULL DEFAULT 0," +
"version INTEGER NOT NULL);" +
"INSERT INTO database (id, version);" +
"SELECT version from databaseOld"
)
}
}

and even this.

What does Firestore Caching do?

This feature caches a copy of the Cloud Firestore data that your app is actively using, so your app can access the data when the device is offline. You can write, read, listen to, and query the cached data. When the device comes back online, Cloud Firestore synchronizes any local changes made by your app to the Cloud Firestore backend.

So if you use Firebase as a backend and Room to store data locally, Firestore Caching may be the perfect fit for you.

Is Firestore Caching really for you?

Firestore Caching is ideal for storing small data that does not contain your users’ sensitive information and then reusing all or most of it. Because, Firestore when saving your data locally transforms it into a data bundle, which is a serialized group of documents. A disadvantage of this is that you cannot use some of the data without loading all of it. If you will not use all or most of the documentation in that bundle, this method may not be suitable for you.

Getting Started

First of all, you don’t need to do something to open this feature, because it comes open in Android & iOS. But if you don’t want, you can disable it like this:

val settings = firestoreSettings {
isPersistenceEnabled = false
}
db.firestoreSettings = settings

Adjusting Cache Size

The default cache size threshold is 100 MB. Configure “setCacheSizeBytes” for a different threshold (minimum 1 MB) or set it to “CACHE_SIZE_UNLIMITED” to disable clean-up.

val settings = FirebaseFirestoreSettings.Builder()
.setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
.build()
db.firestoreSettings = settings

Okay, let’s see an example

Let’s say you have an application like Medium and you want to allow users to read their favorite articles offline, too.

If you do not specify any source, Firestore first tries to read the data from the server, while if Firestore does not receive a response from the server, it starts the client in offline mode and loads the cached data. It also updates the data after it goes online.

So, Firestore Caching works properly without having to do anything.

fun getFavorites() {
firestore.collection("favorites").addSnapshotListener { value, error ->
if (error != null) {
...
} else if (value != null) {
...
}
}
}

If you want data to be retrieved primarily from the cache, you need to call the get() function and pass the source, and you can listen to the task with addOnSuccessListener. Also, keep in mind that this function only relies on the cache to retrieve data, so when using this make sure there is already data in the cache, or take your own precautions.

fun getFavoritesFromCache() {
firestore.collection("favorites").get(Source.CACHE).addOnSuccessListener {
...
}
}

Conclusion

Firestore Caching is especially helpful in storing small data, also I find it very helpful in storing actual data in applications such as todo-list or note-taking apps. If you still haven’t decided what to continue with I strongly recommend reading these articles for more information:

--

--