Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
Kotlin SDK

Migrate from the Java SDK to the Kotlin SDK

Nota

¿Qué es el SDK de Kotlin?

El Kotlin SDK es un nuevo cliente Realm SDK desarrollado por completo con el lenguaje de programación Kotlin. El Kotlin SDK utiliza una base de código completamente diferente a la del Java SDK. Está diseñado específicamente para aprovechar las funcionalidades del lenguaje Kotlin, como las corrutinas y las funciones suspend. El Java SDK también admite algunas de estas funcionalidades, así como aplicaciones de Android escritas en Kotlin. Pero el Kotlin SDK es más propio de Kotlin que el Java SDK.

The Java SDK and the Kotlin SDK differ in many ways. On this page, you'll find a high-level comparison of most of the ways the SDKs differ.

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:

  • Congelados por defecto: Todos los objetos están ahora congelados. A diferencia de los objetos activos, los objetos congelados no se actualizan automáticamente tras las escrituras en la base de datos. Aún se puede acceder a objetos activos dentro de una transacción de escritura, pero al pasar un objeto activo fuera de una transacción de escritura, se congela el objeto.

  • Seguridad en el manejo de hilos: Todas las instancias Realm, objetos, resultados de queries y colecciones ahora pueden transferirse entre hilos.

  • Singleton: ahora solo necesitas una instancia de cada reino. No es necesario abrir y cerrar reinos en hilos individuales.

Tip

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.

  • El SDK de Java usó RealmConfiguration.Builder().build() para generar instancias de RealmConfiguration. Con el Kotlin SDK, usa el método RealmConfiguration.create() método companion RealmConfiguration en su lugar.

  • El SDK de Java utilizó el método estático Realm.getInstance() para abrir un realm con una configuración específica. Con el Kotlin SDK, usa el método estático Realm.open() en su lugar.

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());
val config = RealmConfiguration.create(
setOf(Frog::class, Sample::class))
val realm = Realm.open(config)
Log.v("Successfully opened realm:" +
"${realm.configuration.name}")

Opcionalmente, utilice RealmConfiguration.Builder para personalizar aún más su configuración:

Kotlin SDK
val config = RealmConfiguration.Builder(
setOf(Frog::class, Sample::class))
.name(REALM_NAME)
.deleteRealmIfMigrationNeeded()
.directory(PATH)
.encryptionKey(KEY)
.build()
val realm = Realm.open(config)
Log.v("Successfully opened realm:" +
realm.configuration.name
)

En el SDK de Java, los modelos de objetos Realm se declaran de una de dos maneras:

  • ampliar RealmObject

  • implement 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.

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();
}
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.from(
100,
1000)
var objectIdField: ObjectId = ObjectId()
}

Tanto los SDK de Java como de Kotlin declaran relaciones por medio de campos de objeto Realm:

open class Child : RealmObject() {
var frog: Frog? = null
}
public class Child
extends RealmObject {
public Frog frog = null;
}
class Child : RealmObject {
var frog: Frog? = null
}

Con el SDK de Java, puedes definir relaciones uno a muchos con campos de tipo RealmList. El SDK de Kotlin sigue utilizando campos de tipo RealmList, pero se deben instanciar instancias de RealmList con el método complementario realmListOf().

open class Kid : RealmObject() {
var frogs = RealmList<Frog>()
}
public class Kid
extends RealmObject {
public RealmList<Frog> frogs =
new RealmList<Frog>();
}
class Kid : RealmObject {
var frogs: RealmList<Frog> =
realmListOf()
}

Con el Java SDK, era necesario usar la notación @Required para hacer que las listas de elementos primitivos no pudieran ser nulas en los modelos de objetos Realm. El SDK de Kotlin hace que las listas de elementos primitivos no sean nulos de forma predeterminada. Utiliza el operador ? para permitir que una lista de elementos primitivos sea nula.

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>();
}
class Student : RealmObject {
var notes: RealmList<String> =
realmListOf()
var nullableNotes: RealmList<String?> =
realmListOf()
}

The Kotlin SDK introduces new names for the methods that write to realms.

Con el SDK de Java, se podía escribir asincrónicamente en un dominio realm.executeTransactionAsync() con. El SDK de Kotlin utiliza la función de suspensión realm.write().

realm.executeTransactionAsync {
transactionRealm: Realm ->
val sample: Sample =
Sample()
sample.stringField = "Sven"
transactionRealm.copyToRealm(
sample
)
}
realm.executeTransactionAsync(
transactionRealm -> {
Sample sample = new Sample();
sample.stringField = "Sven";
transactionRealm.copyToRealm(sample);
});
realm.write {
// this: MutableRealm
val sample = Sample()
sample.stringField = "Sven"
this.copyToRealm(sample)
}

Con el Java SDK, podrías guardar de manera sincrónica en un Realm con realm.executeTransaction(). El SDK de Kotlin utiliza realm.writeBlocking():

realm.executeTransaction {
transactionRealm: Realm ->
val sample: Sample =
Sample()
sample.stringField = "Sven"
transactionRealm.copyToRealm(
sample
)
}
realm.executeTransaction(
transactionRealm -> {
Sample sample = new Sample();
sample.stringField = "Sven";
transactionRealm.copyToRealm(sample);
});
realm.writeBlocking {
// this: MutableRealm
val sample = Sample()
sample.stringField = "Sven"
this.copyToRealm(sample)
}

There are several differences between queries in the Java SDK and queries in the Kotlin SDK:

val samples =
realm.where(
Sample::class.java
).findAll()
val samplesThatBeginWithN =
realm.where(
Sample::class.java
)
.beginsWith(
"stringField",
"N"
).findAll()
RealmResults<Sample> samples =
realm
.where(Sample.class)
.findAll();
RealmResults<Sample> samplesThatBeginWithN =
realm
.where(Sample.class)
.beginsWith("stringField",
"N")
.findAll();
val samples: RealmResults<Sample> =
realm.query<Sample>().find()
val samplesThatBeginWithN:
RealmResults<Sample> =
realm.query<Sample>(
"stringField BEGINSWITH 'N'"
).find()
val aggregates =
realm.where(
Sample::class.java
)
.distinct("stringField")
.sort(
"stringField",
Sort.ASCENDING
)
.limit(2)
.findAll()
RealmResults<Sample> aggregates =
realm.where(Sample.class)
.distinct("stringField")
.sort("stringField",
Sort.ASCENDING)
.limit(2)
.findAll();
val aggregates: RealmResults<Sample> =
realm.query<Sample>()
.distinct(Sample::stringField.name)
.sort(Sample::stringField.name,
Sort.ASCENDING)
.limit(2)
.find()

En ambos SDK, solo se pueden eliminar objetos activos. El SDK de Kotlin ofrece mutableRealm.findLatest() para acceder a una versión activa de cualquier objeto congelado. En una transacción de escritura, se pueden consultar directamente los objetos activos y eliminarlos sin findLatest() usar.

val sample =
realm.where(
Sample::class.java
).findFirst()
// delete one object synchronously
realm.executeTransaction {
transactionRealm: Realm? ->
sample!!.deleteFromRealm()
}
// delete a query result asynchronously
realm.executeTransactionAsync {
backgroundRealm: Realm ->
backgroundRealm.where(
Sample::class.java
).findFirst()!!.deleteFromRealm()
}
Sample sample =
realm.where(Sample.class)
.findFirst();
// delete one object synchronously
realm.executeTransaction(
transactionRealm ->
sample.deleteFromRealm());
// delete a query result asynchronously
realm.executeTransactionAsync(
backgroundRealm ->
backgroundRealm
.where(Sample.class)
.findFirst()
.deleteFromRealm());
val sample: Sample? =
realm.query<Sample>()
.first().find()
// delete one object synchronously
realm.writeBlocking {
if (sample != null) {
findLatest(sample)
?.also { delete(it) }
}
}
// delete a query result asynchronously
GlobalScope.launch {
realm.write {
query<Sample>()
.first()
.find()
?.also { delete(it) }
}
}

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()

  • A través de RxJava 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.

realm.where(Sample::class.java)
.findAllAsync()
.addChangeListener {
samples: RealmResults<Sample>?,
changeSet: OrderedCollectionChangeSet ->
// log change description
Log.v(
"EXAMPLE",
("Results changed. " +
"change ranges: " +
Arrays.toString(
changeSet
.changeRanges
) +
", insertion ranges: " +
Arrays.toString(
changeSet
.insertionRanges
) +
", deletion ranges: " +
Arrays.toString(
changeSet
.deletionRanges
))
)
}
realm.where(Sample.class).findAllAsync()
.addChangeListener(
(samples, changeSet) -> {
// log change description
Log.v("EXAMPLE",
"Results changed. " +
"change ranges: " +
Arrays.toString(
changeSet
.getChangeRanges()) +
", insertion ranges: " +
Arrays.toString(
changeSet
.getInsertionRanges()) +
", deletion ranges: " +
Arrays.toString(
changeSet
.getDeletionRanges()));
});
// in a coroutine or a suspend function
realm.query<Sample>().asFlow().collect {
results: ResultsChange<Sample> ->
when (results) {
is InitialResults<Sample> -> {
// do nothing with the
// initial set of results
}
is UpdatedResults<Sample> -> {
// log change description
Log.v("Results changed. " +
"change ranges: " +
results.changeRanges +
", insertion ranges: " +
results.insertionRanges +
", deletion ranges: " +
results.deletionRanges
)
}
}
}

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.

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);
});
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()

Con el Java SDK, las migraciones eran un proceso manual. El SDK de Kotlin automatiza las migraciones, pero también te ofrece acceso a una interfaz de realm dinámica similar para modificaciones personalizadas en la lógica de migración.

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());
// 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)

Ahora que comprende las diferencias entre el SDK de Java y el SDK de Kotlin, consulte el resto de la documentación del SDK de Kotlin.

Volver

SDK Telemetry

En esta página