Realm Kotlin 0.4.1 Announcement
Christian MelchiorPublished Jul 16, 2021 • Updated Mar 22, 2023
Rate this announcement
In this blogpost we are announcing v0.4.1 of the Realm Kotlin Multiplatform SDK. This release contains a significant architectural departure from previous releases of Realm Kotlin as well as other Realm SDK’s, making it much more compatible with modern reactive frameworks like Kotlin Flows. We believe this change will hugely benefit users in the Kotlin ecosystem.
Build better mobile apps with Atlas Device Sync: Atlas Device Sync is a fully-managed mobile backend-as-a-service. Leverage out-of-the-box infrastructure, data synchronization capabilities, built-in network handling, and much more to quickly launch enterprise-grade mobile apps. Get started now by build: Deploy Sample for Free!
The Realm Java and Kotlin SDK’s have historically exposed a model of interacting with data we call Live Objects. Its primary design revolves around database objects acting as Live Views into the underlying database.
This was a pretty novel approach when Realm Java was first released 7 years ago. It had excellent performance characteristics and made it possible to avoid a wide range of nasty bugs normally found in concurrent systems.
However, it came with one noticeable drawback: Thread Confinement.
Thread-confinement was not just an annoying restriction. This was what guaranteed that users of the API would always see a consistent view of the data, even across decoupled queries. Which was also the reason that Kotlin Native adopted a similar memory model
But it also meant that you manually had to open and close realms on each thread where you needed data, and it was impossible to pass objects between threads without additional boilerplate.
Both of which put a huge burden on developers.
More importantly, this approach conflicts with another model for working with concurrent systems, namely Functional Reactive Programming (FRP). In the Android ecosystem this was popularized by the RxJava framework and also underpins Kotlin Flows.
In this mode, you see changes to data as immutable events in a stream, allowing complex mapping and transformations. Consistency is then guaranteed by the semantics of the stream; each operation is carried out in sequence so no two threads operate on the same object at the same time.
In this model, however, it isn’t uncommon for different operations to happen on different threads, breaking the thread-confinement restrictions of Realm.
Looking at the plethora of frameworks that support this model (React JS, RxJava, Java Streams, Apple Combine Framework and Kotlin Flows) It becomes clear that this way of reasoning about concurrency is here to stay.
For that reason we decided to change our API to work much better in this context.
So today we are introducing a new architecture, which we internally have called the Frozen Architecture. It looks similar to the old API, but works in a fundamentally different way.
Realm instances are now thread-safe, meaning that you can use the same instance across the entire application, making it easier to pass around with e.g. dependency injection.
All query results and objects from the database are frozen or immutable by default. They can now be passed freely between threads. This also means that they no longer automatically are kept up to date. Instead you must register change listeners in order to be notified about any change.
All modifications to data must happen by using a special instance of a
MutableRealm, which is only available inside write transactions. Objects inside a write transaction are still live.
Opening a realm now only needs to happen once. It can either be stored in a global variable or made available via dependency injection.
You can now safely keep your realm instance open for the lifetime of the application. You only need to close your realm when interacting with the realm file itself, such as when deleting the file or compacting it.
You can only write within write closures, called
writeBlocking. Writes happen through a MutableRealm which is a receiver of the
Or run as a suspend function. Realm automatically dispatch writes to a write dispatcher backed by a background thread, so launching this from a scope on the UI thread like
Since everything is frozen by default, you need to retrieve a live version of the object that you want to update, then write to that live object to update the underlying data in the realm.
Changes to all Realm classes are supported through Flows. Standard change listener API support is coming in a future release.
As all Realm objects are now frozen by default, it is now possible to pass objects between different dispatcher threads without any additional boilerplate:
With the change to frozen architecture, there are some new pitfalls to be aware of:
Unrelated queries are no longer guaranteed to run on the same version.
We will introduce API’s in the future that can guarantee that all operations within a certain scope are guaranteed to run on the same version. Making it easier to combine the results of multiple queries.
Depending on the schema, it is also possible to navigate the entire object graph for a single object. It is only unrelated queries that risk this behaviour.
Storing objects for extended periods of time can lead to Version Pinning. This results in an increased realm file size. It is thus not advisable to store Realm Objects in global variables unless they are unmanaged.
We will monitor how big an issue this is in practise and will introduce future API’s that can work around this if needed. It is currently possible to detect this happening by setting
Ultimately we believe that these drawbacks are acceptable given the advantages we otherwise get from this architecture, but we’ll keep a close eye on these as the API develops further.
We are really excited about this change as we believe it will fundamentally make it a lot easier to use Realm Kotlin in Android and will also enable you to use Realm in Kotlin Multilplatform projects.
You can read more about how to get started at https://docs.mongodb.com/realm/sdk/kotlin-multiplatform/. We encourage you to try out this new version and leave any feedback at https://github.com/realm/realm-kotlin/issues/new. Sample projects can be found here.
The SDK is still in alpha and as such none of the API’s are considered stable, but it is possible to follow our progress at https://github.com/realm/realm-kotlin.
If you are interested about learning more about how this works under the hood, you can also read more here