# Migrating Android Apps from Realm Java SDK to Kotlin SDK

## Introduction

So, it's here! The engineering team has released a major milestone of the Kotlin
SDK. The preview is available to
you to try it and make comments and suggestions.

Until now, if you were using Realm in Android, you were using the Java version of the SDK.  The purpose of the Realm
Kotlin SDK is to be the evolution of the Java one and eventually replace it.  So, you might be wondering if and when you
should migrate to it.  But even more important for your team and your app is what it provides that the Java SDK
doesn't.  The Kotlin SDK has been written from scratch to combine what the engineering team has learned through years of
SDK development, with the expressivity and fluency of the Kotlin language.  They have been successful at that and the
resulting SDK provides a first-class experience that I would summarize in the following points:

- The Kotlin SDK allows you to use expressions that are Kotlin idiomatic—i.e., more natural to the language.
- It uses Kotlin coroutines and flows to make concurrency easier and more efficient.
- It has been designed and developed with Kotlin Multiplatform in mind.
- It has removed the thread-confinement restriction on Java and it directly integrates with the Android lifecycle hooks
  so the developer doesn't have to spin up and tear down a realm instance on every activity lifecycle.
- It's the way forward.  MongoDB is not discontinuing the Java SDK anytime soon, but Kotlin provides the engineering
  team more resources to implement cooler things going forward. A few of them have been implemented already.  Why wouldn't
  you want to benefit from them?

Are you on board?  I hope you are, because through the rest of this article, I'm going to tell you how to upgrade your
projects to use the Realm Kotlin SDK and take advantage of those benefits that I have just mentioned and some more.  You
can also find a complete code example in this repo.

> **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!

## Gradle build files

First things first.  You need to make some changes to your `build.gradle` files to get access to the Realm Kotlin SDK
within your project, instead of the Realm Java SDK that you were using. The Realm Kotlin SDK uses a gradle plugin that
has been published in the Gradle Plugin Portal, so the prefered way
to add it to your project is using the plugins section of the build configuration of the module —i.e.,
`app/build.gradle`— instead of the legacy method of declaring the dependency in the `buildscript` block of the
project `build.gradle`.

After replacing the plugin in the module configuration with the Kotlin SDK one, you need to add an implementation
dependency to your module.  If you want to use Sync with your MongoDB
cluster, then you should use `'io.realm.kotlin:library-sync'`, but if you just want to have local persistence, then
`'io.realm.kotlin:library-base'` should be enough.  Also, it's no longer needed to have a `realm` dsl section in the
`android` block to enable sync.

### `build.gradle` Comparison

#### Java SDK

```kotlin
buildscript {
// ...
    dependencies {
        classpath "com.android.tools.build:gradle:$agp_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // Realm Plugin
        classpath "io.realm:realm-gradle-plugin:10.10.1"
    }
}
```

#### Kotlin SDK

```kotlin
buildscript {
// ...
    dependencies {
        classpath "com.android.tools.build:gradle:$agp_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
```

### `app/build.gradle` Comparison

#### Java SDK

```kotlin
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id 'realm-android'
}
android {
// ...
    realm {
        syncEnabled = true
    }
}
dependencies {
// ...
}
```

#### Kotlin SDK

```kotlin
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id 'io.realm.kotlin' version '0.10.0'
}
android {
// ...
}
dependencies {
// ...
    implementation("io.realm.kotlin:library-base:0.10.0")
}
```

If you have more than one module in your project and want to pin the version number of the plugin for all of them, you
can define the plugin in the project `build.gradle` with the desired version and the attribute `apply false`.  Then, the
`build.gradle` files of the modules should use the same plugin id, but without the version attribute.

### Multimodule Configuration

#### Project build.gradle

```kotlin
plugins {
// ...
    id 'io.realm.kotlin' version '0.10.0' apply false
}
```

#### Modules build.gradle

```kotlin
plugins {
// ...
    id 'io.realm.kotlin'
}
```

## Model classes

Kotlin scope functions (i.e., `apply`, `run`, `with`, `let`, and `also`) make object creation and manipulation easier.
That was already available when using the Java SDK from kotlin, because they are provided by the Kotlin language itself.

Defining a model class is even easier with the Realm Kotlin SDK.  You are not required to make the model class `open`
anymore.  The Java SDK was using the Kotlin Annotation Processing Tool to derive proxy classes that took care of
interacting with the persistence.  Instead, the Kotlin SDK uses the `RealmObject` interface as a marker for the plugin.
In the construction process, the plugin identifies the objects that are implementing the marker interface and injects the
required functionality to interact with the persistence.  So, that's another change that you have to put in place:
instead of making your model classes extend —i.e., inherit— from `RealmObject`, you just have to implement the interface
with the same name.  In practical terms, this means using `RealmObject` in the class declaration without parentheses.

### Model Class Definition

#### Java SDK

```kotlin
open class ExpenseInfo : RealmObject() {
    @PrimaryKey
    var expenseId: String = UUID.randomUUID().toString()
    var expenseName: String = ""
    var expenseValue: Int = 0
}
```

#### Kotlin SDK

```kotlin
class ExpenseInfo : RealmObject {
    @PrimaryKey
    var expenseId: String = UUID.randomUUID().toString()
    var expenseName: String = ""
    var expenseValue: Int = 0
}
```

There are also changes in terms of the type system.  `RealmList` that was used in the Java SDK to model one-to-many
relationships is extended in the Kotlin SDK to benefit from the typesystem and allow expressing nullables in those
relationships.  So, now you can go beyond `RealmList` and use `RealmList`.  You will get all the
benefits of the syntax sugar to mean that the strings the object is related to, might be null.  You can check this and
the rest of the supported types in the documentation of the Realm Kotlin SDK.

## Opening (and closing) the realm

Using Realm is even easier now.  The explicit initialization of the library that was required by the Realm Java SDK is
not needed for the Realm Kotlin SDK.  You did that invoking `Realm.init()` explicitly.  And in order to ensure that you
did that once and at the beginning of the execution of your app, you normally put that line of code in the `onCreate()`
method of the `Application` subclass.  You can forget about that chore for good.

The configuration of the Realm in the Kotlin SDK requires passing the list of object model classes that conform the
schema, so the `builder()` static method has that as the argument.  The Realm Kotlin SDK also allows setting the logging
level per configuration, should you use more than one.  The rest of the configuration options remain the same.

It's also different the way you get an instance of a Realm when you have defined the configuration that you want to
use.  With the Java SDK, you had to get access to a thread singleton using one of the static methods
`Realm.getInstance()` or `Realm.getDefaultInstance()` (the latter when a default configuration was being set and used).
In most cases, that instance was used and released, by invoking its `close()` method, at the end of the
Activity/Fragment lifecycle.  The Kotlin SDK allows you to use the static method `open()` to get a single instance of a
Realm per configuration.  Then you can inject it and use it everywhere you need it.  This change takes the burden of
Realm lifecycle management off from the shoulders of the developer.  That is huge!  Lifecycle management is often
painful and sometimes difficult to get right.

### Realm SDK Initialization

#### Java SDK

```kotlin
class ExpenseApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        Realm.init(this)

        val config = RealmConfiguration.Builder()
            .name("expenseDB.db")
            .schemaVersion(1)
            .deleteRealmIfMigrationNeeded()
            .build()

        Realm.setDefaultConfiguration(config)
        // Realms can now be obtained with Realm.getDefaultInstance()
    }
}
```

#### Kotlin SDK

```kotlin
class ExpenseApplication : Application() {
    lateinit var realm: Realm

    override fun onCreate() {
        super.onCreate()

        val config = RealmConfiguration
            .Builder(schema = setOf(ExpenseInfo::class))
            .name("expenseDB.db")
            .schemaVersion(1)
            .deleteRealmIfMigrationNeeded()
            .log(LogLevel.ALL)
            .build()

        realm = Realm.open(configuration = config)
        // This realm can now be injected everywhere
    }
}
```

Objects in the Realm Kotlin SDK are now frozen to directly integrate seamlessly into Kotlin coroutine and flows.  That
means that they are not live as they used to be in the Realm Java SDK and don't update themselves when they get changed
in some other part of the application or even in the cloud.  Instead, you have to modify them within a write
transaction, i.e., within a `write` or `writeBlocking` block.  When the scope of the block ends, the objects are frozen
again.

Even better, the realms aren't confined to a thread.  No more thread singletons.  Instead, realms are thread-safe, so
they can safely be shared between threads.  That means that you don't need to be opening and closing realms for the
purpose of using them within a thread.  Get your Realm and use it everywhere in your app.  Say goodbye to all those
lifecycle management operations for the realms!

Finally, if you are injecting dependencies of your application, with the Realm Kotlin SDK, you can have a singleton for
the Realm and let the dependency injection framework do its magic and inject it in every view-model.  That's much easier
and more efficient than having to create one each time —using a factory, for example— and ensuring that the
close method was called wherever it was injected.

## Writing data

It took a while, but Kotlin brought coroutines to Android and we have learned to use them and enjoy how much easier
they make doing asynchronous things.  Now, it seems that coroutines are _the way_ to do those things and we would like
to use them to deal with operations that might affect the performance of our apps, such as dealing with the persistence
of our data.

Support for coroutines and flows is built-in in the Realm Kotlin SDK as a first-class citizen of the API.  You no longer
need to insert write operations in suspending functions to benefit from coroutines.  The `write {}` method of a realm is
a suspending method itself and can only be invoked from within a coroutine context.  No worries here, since the compiler
will complain if you try to do it outside of a context.  But with no extra effort on your side, you will be performing
all those expensive IO operations asynchronously. Ain't that nice?

You can still use the `writeBlocking {}` of a realm, if you need to perform a synchronous operation.  But, beware that,
as the name states, the operation will block the current thread.  Android might not be very forgiving if you block the
main thread for a few seconds, and it'll present the user with the undesirable "Application Not Responding" dialog.  Please,
be mindful and use this **only when you know it is safe**.

Another additional advantage of the Realm Kotlin SDK is that, thanks to having the objects frozen in the realm, we can
make asynchronous transactions easier.  In the Java SDK, we had to find again the object we wanted to modify inside of
the transaction block, so it was obtained from the realm that we were using on that thread.  The Kotlin SDK makes that
much simpler by using `findLatest()` with that object to get its instance in the mutable realm and then apply the
changes to it.

### Asynchronous Transaction Comparison

#### Java SDK

```kotlin
realm.executeTransactionAsync { bgRealm ->
    val result = bgRealm.where(ExpenseInfo::class.java)
        .equalTo("expenseId", expenseInfo.expenseId)
        .findFirst()

    result?.let {
        result.deleteFromRealm()
    }
}
```

#### Kotlin SDK

```kotlin
viewModelScope.launch(Dispatchers.IO) {
    realm.write {
        findLatest(expenseInfo)?.also {
            delete(it)
        }
    }
}
```

## Queries and listening to updates

One thing where Realm shines is when you have to retrieve information from it.  Data is obtained concatenating three
operations:

1. Creating a RealmQuery for the object class that you are interested in.
2. Optionally adding constraints to that query, like expected values or acceptable ranges for some attributes.
3. Executing the query to get the results from the realm.  Those results can be actual objects from the realm, or
   aggregations of them, like the number of matches in the realm that you get when you use `count()`.

The Realm Kotlin SDK offers you a new query system where each of those steps has been simplified.

The queries in the Realm Java SDK used filters on the collections returned by the `where` method.  The Kotlin SDK offers
the `query` method instead.  This method takes a type parameter using generics, instead of the explicit type parameter
taken as an argument of `where` method.  That is easier to read and to write.

The constraints that allow you to narrow down the query to the results you care about are implemented using a predicate
as the optional argument of the `query()` method.  That predicate can have multiple constraints concatenated with
logical operators like `AND` or `OR` and even subqueries that are a mayor superpower that will boost your ability to
query the data.

Finally, you will execute the query to get the data.  In most cases, you will want that to happen in the background so
you are not blocking the main thread.  If you also want to be aware of changes on the results of the query, not just the
initial results, it's better to get a flow.  That required two steps in the Java SDK.  First, you had to use
`findAllAsync()` on the query, to get it to work in the background, and then convert the results into a flow with the
`toFlow()` method.  The new system simplifies things greatly, providing you with the `asFlow()` method that is a
suspending function of the query.  There is no other step.  Coroutines and flows are built-in from the beginning in the
new query system.

### Query Comparison

#### Java SDK

```kotlin
private fun getAllExpense(): Flow> =
    realm.where(ExpenseInfo::class.java).greaterThan("expenseValue", 0).findAllAsync().toFlow()
```

#### Kotlin SDK

```kotlin
private fun getAllExpense(): Flow> =
    realm.query("expenseValue > 0").asFlow()
```

As it was the case when writing to the Realm, you can also use blocking operations when you need them, invoking `find()`
on the query.  And also in this case, use it **only when you know it is safe**.

## Conclusion

You're probably not reading this, because if I were you, I would be creating a branch in my project and trying the
Realm Kotlin SDK already and benefiting from all these wonderful changes.  But just in case you are, let me summarize the
most relevant changes that the Realm Kotlin SDK provides you with:

- The configuration of your project to use the Realm Kotlin SDK is easier, uses more up-to-date mechanisms, and is more
  explicit.
- Model classes are simpler to define and more idiomatic.
- Working with the realm is much simpler because it requires less ceremonial steps that you have to worry about and
  plays better with coroutines.
- Working with the objects is easier even when doing things asynchronously, because they're frozen, and that helps you
  to do things safely.
- Querying is enhanced with simpler syntax, predicates, and suspending functions and even flows.

Time to code!