Simplest REST data persistence for Android with Kotlin, Retrofit, DBFlow and Rx

Samuel Koprivnjak
AndroidPub
Published in
4 min readApr 16, 2018
Photo by Baher Khairy on Unsplash

Just stop and think how many times you had to implement simple mobile rest client whose primary function is to consume and store the server data.

I often traverse through various open source projects, and still I didn’t find clean and short straightforward solution for this. Projects that I inherited often use their own, custom made implementation of parser and object mapper including lots of boilerplate code that makes everything harder to understand, extend and debug. That’s why I tried to design my own toolkit that will handle such scenario in generic, simple way and could be reusable across different projects.

This solution will leverage the power of Retrofit, Gson, DBFlow and Rx libraries. Whole working example (with project setup) can be seen on my github repo.

This is how the toolkit looks like:
1. Retrofit is handling the HTTP API calls and Json with Gson converter
2. DBFlow is used for database persistence (ORM — Object-relational mapping) — database binding and transactions
3. RxKotlin manages asynchronous tasks — running network calls, handling the data, and reporting the result to subscriber (chaining actions and emitting the results)

1. Retrofit

I used Gson serializer for converting the HTTP responses to Java objects. First we need to define the API routes and JSON models. We use simple Kotlin data classes that serializer can easily convert to/from Json.

Country Json object
Country data class

In this way Json array of countries can easily be converted by Gson converter to list of Country classes that we can then use in our code.

Retrofit HTTP API routes and expected types

Through annotations Retrofit will route our getCountry()method to the written HTTP route v1/api/countriesand return to us the expected type List<Country>.

So this is enough for fetching the requested data and preparing if for usage in code. Next we want to store this data into our local storage. That’s why we would need ORM library.

2. DBFlow

Even though this is not the currently most hyped ORM library (like Room), I choose it because of excellent performance, no too much boiler-plate, nice migration support, preloaded database support and while it is one of the most mature ORM libraries. I ran into all kind of easy and complex requirements for database storage and queries and DBFlow has never failed to provide solution.

We need to convert data class to be DBFlow data model. We do this by modifying our existing data class.

DBFlow data model

By using annotations we are specifying the table name in our local SQLite database, automatically including all variables as columns, using SQL statements that will handle data conflicts by inserting latest data, setting the Primary Key.

We are also providing default values for fields, because DBFlow needs this to correctly generate default constructor.

Data class is now using mutable var variable instead of immutable val variable because we need getters and setters automatically generated for DBFlow models.

By extending BaseModel class we are inheriting methods for save, update, delete operations and can now easily write type safe queries, just as I’ve did in previous example with static method getAll().

Kotlin infix operators are also convenient and providing us with ability to write SQLite operations with easier to read syntax (C#-like LINQ syntax).

DBFlow query LINQ like syntax

3. RxKotlin

RxJava (library for composing asynchronous and event-based programs by using observable sequences) which is base for RxKotlin is very powerful but complicated and has steep learning curve (big API), but I will try to use it as simple as possible — for chaining the network calls, running actions on separate threads and reporting back the result. I will aggregate the HTTP results and store fetched data through database transaction. In this way this whole procedure will produce consistent data and predictable results.

Method that will executes on IO thread 2 HTTP calls (getCountries and getTourists) and store the results

First we are executing 2 HTTP API calls who emit successful responses (data objects — countries and tourists), which have been automatically deserialized. I am then making list of those combined data so I can store them in one transaction (I am using Kotlin spread operator *countriesto expand the data to new list).

Method that saves all items through database transaction and provides Rx Completable interface

Then this list of objects (records) is being stored through transaction in database. This is a generic method that can handle all persistable objects (explained in DBFlow data model adaptation step).

When all those actions succeed the procedure is completed, and we have stored rest objects in our local database that we can now use. We will validate it with simple query method in success callback of Rx method (look subscribe callback of getCountryTourist() method).

I am using Completablereactive base class because I don’t need to stream results, but just get notification when everything is done.

In my example on github you can see whole code with all imports and simple proof of concept in MainActivity. I used fake HTTP interceptor for simulating the Json responses, so I would recommend to have a look at it.

Thank you for reading till now, and happy coding :)

--

--

Samuel Koprivnjak
AndroidPub

Besides kicking volleyball, playing jazz piano, I design software, manage team and myself in the first place