Using Realm persistence library in a Kotlin Multiplatform project
Posted on May 6, 2021
It’s always great to see the Kotlin Multiplatform (KMP) library ecosystem continuing to grow and a relatively new addition to that is
Realm which describes itself as “a mobile database that runs directly inside phones, tablets or wearables.” and “a replacement for SQLite & ORMs”.
An added positive is fact that it’s another example of existence now of multiple different KMP libraries addressing particular functionality…with for
example SQLDelight, Kodein-DB, and, somewhat indirectly,
Apollo GraphQL libraries providing persistence capabilities (previous articles
here have described integrating those). Realm KMP library is in developer preview right now, and is still undergoing active development, but I thought it would be
interesting to explore adding it as persistence layer for a KMP sample, FantasyPremierLeague,
that I created recently (note that the changes shown here have been pushed to the realm branch of that repo).
Check out the story of Realm's Kotlin Multiplatform SDK!
Learn what motivated their Engineering team’s decision to build a new SDK and the key design principles that guided their development.https://t.co/EnKFGoqVLj
As a point of reference this is what the UI looks like for our iOS and Android apps
Setup
To use Realm in the project we firstly added following to root build.gradle.kts
repositories:
dependencies:
And, in build.gradle.kts for the KMP shared code module, we add:
plugins:
commonMain dependencies:
Shared code updates
The FantasyPremierLeague repo includes a class, FantasyPremierLeagueRepository, which exposes
API from shared code for accessing for example list of players and game fixtures. In initial implementation there was no persistence and each time
these methods were called they’d make remote API requests (using FantasyPremierLeagueApi which in turn makes use of Ktor library).
To start using Realm we firstly need to define our data model as shown below. Note here that both PlayerDb and FixtureDb refer to TeamnDb
.
Next up we create our Realm instance
Now we can start using this to write data to the database and also to observe database changes which we’ll ultimately now use to drive updates to the UI.
In our initial basic implementation we read data from remote api endpoint and store to database on startup using following.
Now we can observe updates to the database using following code. Any changes are mapped to the data model classes
that we’re exposing from our repository (e.g. Player and GameFixture) and stored in StateFlow variables.
Android related updates
In our Android ViewModel we can reference the StateFlow variables exposed from our repository (in this example we’re combining with
possible search term for a player)
And then in our Jetpack Compose code we can finally use this to show list of players in UI.
iOS related updates
There are a number of different approaches that can be used to expose Flows from shared code to iOS clients but in this case
we’re going to just pass lambda/closure from our Swift ViewModel to following method in FantasyPremierLeagueRepository
This is then what our iOS Swift ViewModel looks like
And finally this is part of SwiftUI code used to render the list of players.