Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/

从 Java SDK 迁移到 Kotlin SDK

在此页面上

  • Overview
  • Kotlin SDK 架构
  • 打开域
  • Realm 对象模型
  • 关系
  • 一对一
  • 一对多
  • 模式类型
  • 写入
  • 异步
  • 同步
  • 查询
  • 筛选器
  • 排序、去重和限制
  • 删除
  • 通知
  • 线程
  • 迁移
  • 下一步

注意

什么是 Kotlin SDK?

Kotlin SDK 是完全使用 Kotlin 编程语言构建的全新 Realm 客户端 SDK。Kotlin SDK 使用与 Java SDK 完全不同的代码库,专为利用 Kotlin 语言功能(如协程和挂起函数)而设计。Java SDK 还支持其中一些功能以及用 Kotlin 编写的 Android 应用程序。但 Kotlin SDK 比 Java SDK 更符合 Kotlin 习惯。

Java SDK 和 Kotlin SDK 在很多方面有所不同。在本页面中,您将发现大多数 SDK 不同之处的高级比较。

Java SDK 提供了活动对象、查询和域,这些对象、查询和领域会在底层数据发生变化时自动更新。Kotlin SDK 仍然在写事务中提供此活动接口,但在其他事务中会依赖新的冻结架构,该架构降低了 Realm 对象的处理难度。以下是 Java SDK 架构与 Kotlin SDK 架构的一些主要区别:

  • 默认已冻结:现在所有对象都已冻结。与活动对象不同,冻结对象在数据库写入后不会自动更新。您仍然可以在写事务中访问活动对象,但将活动对象传递出写入事务会冻结该对象。

  • 线程安全性:所有 Realm 实例、对象、查询结果和集合现在都可以跨线程传输。

  • Singleton :现在每个域只需要一个实例。 无需在单个线程上打开和关闭 Realm。

提示

另请参阅:

Java SDK 会自动检测应用程序中定义的 Realm 对象模型,并在打开的 Realm 模式中使用所有这些对象模型,除非您另外指定。Kotlin SDK 要求您手动指定要在 Realm 模式中使用的 Realm 对象模型。 此外:

  • Kotlin SDK 不提供在应用程序中设置和访问默认 Realm 的功能。 由于您现在可以跨线程共享 Realm、对象和结果,因此您可以改为依赖全局单例。

  • Java SDK 使用RealmConfiguration.Builder().build()生成RealmConfiguration的实例。 对于 Kotlin SDK,请使用RealmConfiguration.create() 伴随方法RealmConfiguration

  • Java SDK 使用静态Realm.getInstance()方法打开具有给定配置的 Realm。 使用 Kotlin SDK,请改用静态 Realm.open() 方法。

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}")

或者,使用 RealmConfiguration.Builder 进一步自定义配置:

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
)

提示

另请参阅:

在 Java SDK 中,您可以通过以下两种方式之一来声明 Realm 对象模型:

  • 扩展 RealmObject

  • 实施 RealmModel

Kotlin SDK 改用 RealmObject 接口中的默认方法。对于 Kotlin SDK,从 RealmObject 继承以声明 Realm 对象模型。对于具有特殊属性的字段,如忽略的字段、主键和索引,注释的工作方式与 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();
}
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()
}

提示

另请参阅:

Java 和 Kotlin SDK 都通过 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
}

使用 Java SDK,您可以定义与RealmList类型字段的一对多关系。 Kotlin SDK 仍然使用RealmList类型的字段,但您应使用realmListOf()伴随方法实例化RealmList实例。

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

对于 Java SDK,您需要使用 @Required 注释使基元列表在 Realm 对象模型中不可为空。Kotlin SDK 默认使基元列表不可为空。使用 ? 操作符,使基元列表可为空。

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

Kotlin SDK 为写入 Realm 的方法引入了新名称。

使用 Java SDK,您可以异步写入具有 realm.executeTransactionAsync()的域。 Kotlin SDK 改用挂起函数 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)
}

使用 Java SDK,您可以同步写入具有realm.executeTransaction()的 Realm。 Kotlin SDK 使用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)
}

Java SDK 中的查询与 Kotlin SDK 中的查询有几处不同:

  • 借助 Java SDK,您可以使用流式接口或 Realm 查询语言(RQL) 查询域中的对象。Kotlin SDK 仅使用 RQL。

  • Java SDK 使用realm.where()来查询域,而 Kotlin SDK 使用realm.query()。

  • 借助 Java SDK,您可以使用realmQuery.findAllAsync()realmQuery.findFirstAsync()进行异步查询。 在 Kotlin SDK 中,使用realmQuery.asFlow()进行异步查询。 获得结果流后,您可以 收集 结果。

  • 借助 Java SDK,您可以使用realmQuery.findAll()realmQuery.findFirst()进行同步查询。 在 Kotlin SDK 中,使用realmQuery.find() 进行同步查询。

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

在这两个 SDK 中,您只能删除活动对象。 Kotlin SDK 提供了mutableRealm.findLatest() 访问任何冻结对象的活动版本。 在写事务中,您可以直接查询和删除活动对象,而无需使用findLatest()

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

在这两个 SDK 中,您都可以订阅结果集合的变化。借助 Java SDK,只要域结果发生变化,您就可以通过以下接口收到通知:

  • realmResults.addChangeListener()

  • RxJava,通过 asFlowable()

  • Kotlin 扩展,带有 toFlow()

Kotlin SDK 会用realmQuery.asFlow()替换所有这些选项。 获得 结果流后,您可以调用 对方付费 订阅变更。该流程发出的任何类型为UpdatedResults的对象都表示对结果集的更改。

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

对于 Java SDK,Realm、Realm 对象和结果不能在线程之间传递。Kotlin SDK 默认会冻结这些对象,使其具有线程安全性。与 Java SDK 使用的活动对象不同,Kotlin SDK 中的冻结对象不会在底层数据变更时自动更新。对于 Kotlin SDK,您必须使用通知来订阅更新。

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

提示

另请参阅:

对于 Java SDK,迁移是手动进程。Kotlin SDK 可自动执行迁移,还允许您访问类似的动态 Realm 接口,对迁移逻辑进行自定义调整。

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)

现在您已经了解了 Java SDK 和 Kotlin SDK 的区别,请查看 Kotlin SDK 文档 的其他部分。

后退

SDK 遥测