The Kotlin SDK is a new Realm client SDK built entirely with the
Kotlin programming language. The Kotlin SDK uses an entirely
different codebase from the Java SDK. It is designed specifically
to take advantage of Kotlin language features such as coroutines and
suspend functions. The Java SDK also supports some of these features,
as well as Android applications written in Kotlin. But the
Kotlin SDK is more Kotlin-idiomatic than the
Java SDK.
The Java SDK provided live objects, queries, and realms that
automatically update when underlying data changes. The Kotlin SDK still
provides this live interface in write transactions, but otherwise relies
on a new frozen architecture that makes Realm objects easier to work
with. Here are some of the main differences between the Java SDK
architecture and the Kotlin SDK architecture:
Frozen by default: All objects are now frozen. Unlike live objects,
frozen objects do not automatically update after database writes. You
can still access live objects within a write transaction, but passing
a live object out of a write transaction freezes the object.
Thread-safety: All realm instances, objects, query results, and
collections can now be transferred across threads.
The Java SDK automatically detects Realm Object Models defined in your
application, and uses all of them in the schema of opened realms unless
you specify otherwise. The Kotlin SDK requires you to manually specify
the Realm Object Models to use in your realm schema. Additionally:
The Kotlin SDK does not provide the ability to set and access a
default realm in your application. Since you can now share realms,
objects, and results across threads, you can rely on a global singleton
instead.
The Java SDK used RealmConfiguration.Builder().build() to
generate instances of RealmConfiguration. With the Kotlin SDK,
use the RealmConfiguration.with()
companion method RealmConfiguration instead.
The Java SDK used the static Realm.getInstance() method to
open a realm with a given config. With the Kotlin SDK, use the static
Realm.open() method instead.
Java SDK (Kotlin)
Java SDK (Java)
val config = RealmConfiguration.Builder() .build() var realm: Realm realm = Realm.getInstance(config) Log.v( "EXAMPLE", "Successfully opened a realm: " + realm.path )
RealmConfiguration config = new RealmConfiguration.Builder() .build(); Realm realm; realm = Realm.getInstance(config); Log.v("EXAMPLE", "Successfully opened a realm: " + realm.getPath());
Kotlin SDK
val config = RealmConfiguration .with(schema = setOf(Frog::class, Sample::class)) val realm = Realm.open(config) Log.v("Successfully opened realm:" + "${realm.configuration.name}")
In the Java SDK, you declare Realm object models in one of two ways:
extending RealmObject
implementing RealmModel
The Kotlin SDK uses default methods in the RealmObject interface
instead. With the Kotlin SDK, inherit from RealmObject to
declare a Realm object model. Annotations work the same way they did
in java for fields with special properties, such as ignored fields,
primary keys, and indexes.
Java SDK (Kotlin)
Java SDK (Java)
open class Sample : RealmObject() { @PrimaryKey var stringField = "Realm" var byteField: Byte = 0xA // no support for chars: no charField var shortField: Short = 17 var intField = 42 @Index var longField = 256L var booleanField = true var floatField = 3.14f var doubleField = 1.19840122 var timestampField = Date() }
public class Sample extends RealmObject { @PrimaryKey public String stringField = "Realm"; public Byte byteField = 0xA; // no support for chars: no charField public Short shortField = 17; public Integer intField = 42; @Index public Long longField = 256L; public Boolean booleanField = true; public Float floatField = 3.14f; public Double doubleField = 1.19840122; public Date timestampField = new Date(); }
Kotlin SDK
class Sample : RealmObject { @PrimaryKey var stringField: String = "Realm" var byteField: Byte = 0xA var charField: Char = 'a' var shortField: Short = 17 var intField: Int = 42 @Index var longField: Long = 256L var booleanField: Boolean = true var floatField: Float = 3.14f var doubleField: Double = 1.19840122 var timestampField: RealmInstant = RealmInstant.fromEpochSeconds( 100, 1000) }
With the Java SDK, you could define one-to-many relationships with fields
of type RealmList. The Kotlin SDK still uses fields of
type RealmList, but you should instantiate RealmList
instances with the realmListOf()
companion method.
Java SDK (Kotlin)
Java SDK (Java)
open class Kid : RealmObject() { var frogs = RealmList<Frog>() }
public class Kid extends RealmObject { public RealmList<Frog> frogs = new RealmList<Frog>(); }
Kotlin SDK
class Kid : RealmObject { var frogs: RealmList<Frog> = realmListOf() }
With the Java SDK, you needed to use the @Required annotation to
make lists of primitives non-nullable in realm object models. The Kotlin
SDK makes lists of primitives non-nullable by default. Use the
? operator to make a list of primitives nullable.
Java SDK (Kotlin)
Java SDK (Java)
open class CollegeStudent : RealmObject() { @Required var notes = RealmList<String>() var nullableNotes = RealmList<String>() }
public class CollegeStudent extends RealmObject { @Required public RealmList<String> notes = new RealmList<String>(); public RealmList<String> nullableNotes = new RealmList<String>(); }
Kotlin SDK
class Student : RealmObject { var notes: RealmList<String> = realmListOf() var nullableNotes: RealmList<String?> = realmListOf() }
With the Java SDK, you could write asynchronously to a realm with
realm.executeTransactionAsync(). The Kotlin SDK uses
the suspend function realm.write() instead.
There are several differences between queries in the Java SDK and queries
in the Kotlin SDK:
With the Java SDK, you can query objects in realms using a fluent
interface or Realm Query Language (RQL).
The Kotlin SDK only uses RQL.
The Java SDK uses realm.where()
to query realms, whereas the Kotlin SDK uses realm.query().
With the Java SDK, you could query asynchronously with
realmQuery.findAllAsync() and realmQuery.findFirstAsync().
In the Kotlin SDK, query asynchronously with
realmQuery.asFlow().
Once you have a flow of results, you can collect()
the results.
With the Java SDK, you could query synchronously with
realmQuery.findAll() and realmQuery.findFirst().
In the Kotlin SDK, query synchronously with
realmQuery.find().
In both SDKs, you can subscribe to change to collections of results.
With the Java SDK, you could receive notifications whenever realm results
changed with the following interfaces:
realmResults.addChangeListener()
RxJava through asFlowable()
Kotlin Extensions with toFlow()
The Kotlin SDK replaces all of these options with realmQuery.asFlow().
Once you have a flow of results, you can call collect()
to subscribe to changes. Any object of type UpdatedResults emitted
by the flow represents a change to the results set.
With the Java SDK, realms, Realm objects, and results cannot be passed
between threads. The Kotlin SDK freezes these objects by default, making
them thread-safe. Unlike the live objects used by the Java SDK, the
frozen objects found in the Kotlin SDK do not automatically update when
underlying data changes. With the Kotlin SDK, you must use notifications to subscribe to
updates instead.
Java SDK (Kotlin)
Java SDK (Java)
realm = Realm.getInstance(config) val sample = realm.where( Sample::class.java ).findFirst() // save sample field in a // separate variable // for access on another thread val sampleStringField = sample!!.stringField val executorService = Executors.newFixedThreadPool(4) executorService.execute { // cannot pass a realm // into another thread, // so get a new instance // for separate thread val threadRealm = Realm.getInstance(config) // cannot access original // sample on another // thread, use // sampleStringField instead val threadSample = threadRealm.where( Sample::class.java ) .equalTo( "stringField", sampleStringField ).findFirst() Log.v( "EXAMPLE", "Separate thread sample: " + threadSample ) }
realm = Realm.getInstance(config); Sample sample = realm .where(Sample.class).findFirst(); // save sample field in a variable // for access on another thread String sampleStringField = sample.stringField; ExecutorService executorService = Executors.newFixedThreadPool(4); executorService.execute(() -> { // cannot pass a realm // into another thread, // so get a new instance // for separate thread Realm threadRealm = Realm.getInstance(config); // cannot access original // sample on another // thread, use // sampleStringField instead Sample threadSample = threadRealm .where(Sample.class) .equalTo("stringField", sampleStringField) .findFirst(); Log.v("EXAMPLE", "Separate thread sample: " + threadSample); });
Kotlin SDK
val realm = Realm.open(config) val sample: Sample? = realm.query<Sample>() .first() .find() launch(Dispatchers.Unconfined) { // can access the realm opened on // a different thread realm.query<Sample>().find() // can access realm object queried // on a different thread Log.v(sample!!.stringField) }.join()
With the Java SDK, migrations were a manual process. The Kotlin SDK
automates migrations, but also gives you access to a similar dynamic
realm interface for custom tweaks to migration logic.
Java SDK (Kotlin)
Java SDK (Java)
val config = RealmConfiguration.Builder() .migration { realm: DynamicRealm, oldVersion: Long, newVersion: Long -> val schema: RealmSchema = realm.schema if (oldVersion == 0L) { // perform schema migration schema.get("Sample") ?.addField( "new_field", String::class.java ) } // migrate data schema.get("Sample") ?.transform { obj: DynamicRealmObject -> obj.set( "longField", 42L ) } }.build() val realm: Realm = Realm.getInstance(config) Log.v( "EXAMPLE", "Successfully opened a realm: " + realm.path )
RealmConfiguration config = new RealmConfiguration.Builder() .migration((realm, oldVersion, newVersion) -> { RealmSchema schema = realm.getSchema(); if (oldVersion == 0L) { // perform schema migration schema.get("Sample") .addField("new_field", String.class); } // migrate data schema.get("Sample") .transform(obj -> obj.set("longField", 42L)); }).build(); Realm realm; realm = Realm.getInstance(config); Log.v("EXAMPLE", "Successfully opened a realm: " + realm.getPath());
Kotlin SDK
// A Realm migration that performs // automatic schema migration // and allows additional custom // migration of data. RealmConfiguration.Builder( schema = setOf(Sample::class)) .migration(AutomaticSchemaMigration { context: AutomaticSchemaMigration.MigrationContext -> val oldRealm: DynamicRealm = context.oldRealm val newRealm: DynamicMutableRealm = context.newRealm // dynamic realm gives access // to realm data // through a generic string // based API context.enumerate("Sample") { oldObject: DynamicRealmObject, newObject: DynamicMutableRealmObject? -> newObject?.set("longField", 42L) } }) .build() val realm = Realm.open(config)