配置并打开 Realm - Kotlin SDK
在此页面上
本页介绍 Realm 文件以及如何配置、打开和关闭仅在本地持久保存数据的 Realm。 要打开使用 Device Sync 与 Atlas 同步数据的 Realm,请参阅打开同步 Realm。
域是Realm中用于组织数据的核心数据结构。 每个域都是Realm对象的集合:您在应用程序中使用的对象以及描述这些对象的其他元数据。 每个Realm 对象类型都有一个基于您定义的对象模型的对象对象模式。
Realm 模式是 Realm 可能包含的有效对象模式的列表。 您可以在打开 Realm 时指定模式。 如果在打开 Realm 时已包含数据,则 Realm 会验证每个对象,以确保为其类型提供了对象模式,并且满足模式中指定的所有约束。
Realm 文件
Realm 将 Realm 中每个对象和类型的二进制编码版本存储在单个 .realm
文件中。当您打开一个域时,Realm会创建.realm
文件(如果该文件尚不存在)。该文件位于特定路径,您可以在打开 Realm 时定义该路径。
如果您不想创建.realm
文件或其关联的辅助文件,可以打开内存中域。 有关更多信息,请参阅打开内存中Realm部分。
辅助文件
Realm 会为每个 Realm 创建附加文件:
realm 文件,后缀为 "realm",例如
default.realm
:包含对象数据。锁定文件,后缀为 "lock",例如
default.realm.lock
:跟踪 Realm 中哪些数据版本正在使用中。 这可以防止 Realm 回收客户端应用程序仍在使用的存储空间。note 文件,后缀为 "note",例如
default.realm.note
:启用线程间和进程间通知。管理文件,后缀为“管理”,例如
default.realm.management
:内部状态管理。
删除这些文件具有重要意义。 有关删除.realm
或辅助文件的更多信息,请参阅:删除Realm。
打开 Realm
要打开 Realm,请创建一个定义 Realm 详细信息的RealmConfiguration对象。 然后,将生成的RealmConfiguration
传递给Realm.open()。
您可以使用默认配置值打开 Realm,也可以使用其他配置选项构建RealmConfiguration
。 但是,您必须传递一个模式参数,其中包括要在 Realm 中使用的所有对象类。
使用所需配置打开域后,您可以根据定义的模式读取和写入数据。
本页上的示例引用了以下 Realm 对象:
class Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" } class Person : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" }
打开默认 Realm
要使用默认配置值打开域 ,请使用RealmConfiguration.create() 。 方法。 您只需要将一设立对象类定义为域模式。 然后,将RealmConfiguration
传递给Realm.open()。
以下示例在默认路径中打开一个default.realm
文件,其模式包括Frog
和Person
类:
// Creates a realm with default configuration values val config = RealmConfiguration.create( // Pass object classes for the realm schema schema = setOf(Frog::class, Person::class) ) // Open the realm with the configuration object val realm = Realm.open(config) Log.v("Successfully opened realm: ${realm.configuration.name}") // ... use the open realm ...
默认文件位置
如果没有为域文件定义目录,则使用平台的默认应用存储位置。 您可以使用以下命令查找平台的默认目录:
Android:
Context.getFiles()
Java虚拟机(JVM):
System.getProperty("user.dir")
macOS:
platform.Foundation.NSFileManager.defaultManager.currentDirectoryPath
iOS:
NSFileManager.defaultManager.URLForDirectory( NSDocumentDirectory, NSUserDomainMask, null, true, null )
打开内存中 Realm
您可以完全在内存中打开域 ,这样不会创建.realm
文件或其关联的辅助文件。 相反,SDK 会在域打开时将对象存储在内存中,然后在关闭所有实例时丢弃数据。
要打开在不写入文件的情况下运行的 Realm,请通过RealmConfiguration.Builder 并使用inMemory属性来构建RealmConfiguration
。 然后,将生成的RealmConfiguration
传递给Realm.open():
// Create the in-memory realm configuration val config = RealmConfiguration.Builder( schema = setOf(Frog::class, Person::class) ) .inMemory() .build() // Open the realm with the configuration object val realm = Realm.open(config) Log.v("Successfully opened an in-memory realm") // ... use the open realm ...
注意
内存中的 Realm 不会被持久化
由于内存中的 Realm 不会持久保存,因此,只要您想要访问数据,请确保至少有一个处于打开状态的 Realm 实例。 关闭内存中 Realm 的最后一个实例后,数据就不再可用。
自定义 Realm 配置
您可以向RealmConfiguration
添加可选参数,以控制要打开的域的细节,包括:
有关特定配置实现的更多信息,请参阅管理Realm文件 - Kotlin SDK。
要使用非默认值配置 Realm,请通过RealmConfiguration.Builder.build()创建RealmConfiguration
并传递您要设置的任何属性。 然后,将生成的RealmConfiguration
传递给Realm.open()。
在以下示例中, RealmConfiguration
指定自定义名称和目录 ("my-directory-path/myRealmName.realm") 以及加密密钥:
// Create a realm configuration with configuration builder // and pass all optional arguments val config = RealmConfiguration.Builder( schema = setOf(Frog::class, Person::class) ) .name("myRealmName.realm") .directory("my-directory-path") .encryptionKey(myEncryptionKey) .build() // Open the realm with the configuration object val realm = Realm.open(config) Log.v("Successfully opened realm: ${realm.configuration.name}") // ... use the open realm ...
将初始数据添加到 Realm
您可以使用initialDataCallback将初始数据添加到域 。 首次打开域时会触发该回调。
val config = RealmConfiguration.Builder( schema = setOf(Frog::class, Person::class) ) .initialData { copyToRealm(Frog().apply { name = "Kermit" }) copyToRealm(Person().apply { name = "Jim Henson" }) } .build() val realm = Realm.open(config) Log.v("Successfully opened realm: ${realm.configuration.name}") // Opened realm includes the initial data val initialFrog = realm.query<Frog>().find().first() val initialPerson = realm.query<Person>().find().first() Log.v("Realm initialized with: ${initialFrog.name} and ${initialPerson.name}")
查找 Realm 文件路径
要查找.realm
文件的文件路径,请使用realm.configuration.path属性:
val realmPath = realm.configuration.path Log.v("Realm path: $realmPath")
关闭 Realm
您可以使用realm.close()关闭一个 Realm。 此方法会阻塞,直到 Realm 上的所有写事务都完成为止。
realm.close()
警告
关闭 Realm 以防止内存泄漏
请务必关闭 Realm 实例以释放资源。 未能关闭 Realm 可能会导致OutOfMemoryError
。
将数据复制到 New Realm
要将数据从现有域复制到具有不同配置选项的新域 ,请将新配置传递给Realm.writeCopyTo() 方法。 示例,您可以通过复制数据来备份本地域或将同步域转换为本地域。
您可以将数据复制到使用相同配置的 Realm:
本地 Realm 到本地 Realm
内存中 Realm 到内存中 Realm
同步 Realm 到同步 Realm
您可以将数据复制到使用不同同步配置的 Realm:
本地域到基于分区的同步域
同步 Realm 到本地域
将同步 Realm 到其他用户的同步 Realm
警告
您无法将数据从本地 Realm 复制到 Flexible Sync Realm。 不能在不同的同步配置类型之间复制,例如 从 基于分区的同步 到Flexible Sync 。
您还可以合并对配置的更改。 示例,您可以将数据从未加密的内存中同步域复制到加密的本地域。
使用 Realm.writeCopyTo()
时需要注意的一些其他注意事项:
目标文件不能是已经存在的文件。
在写事务或迁移过程中,不允许复制 Realm。
使用Device Sync时,必须在写入副本之前将所有本地更改与服务器同步。 这确保该文件可以用作新安装的应用程序的点。 如果有待上传的内容, Realm会引发错误。
您可以使用uploadAllLocalChanges()和downloadAllServerChanges()确保所有同步进程均已完成。
例子
将数据从 Flexible Sync Realm复制到本地Realm
// Instantiate the synced realm with your App ID val app = App.create(YOUR_APP_ID) runBlocking { val user = app.login(credentials) // Create the synced realm configuration val syncConfig = SyncConfiguration.Builder(user, setOf(Frog::class)) .initialSubscriptions { realm -> add(realm.query<Frog>(),"all-frogs") } .build() // Open the synced realm and add data to it val syncRealm = Realm.open(syncConfig) Log.v("Successfully opened realm: ${syncRealm.configuration.name}") syncRealm.write { this.copyToRealm(Frog().apply { name = "Kermit" }) } // Wait for write to sync syncRealm.syncSession.uploadAllLocalChanges(30.seconds) // Create the local realm val localConfig = RealmConfiguration.Builder(setOf(Frog::class)) .name("local.realm") .build() // Copy data from synced realm to the new realm syncRealm.writeCopyTo(localConfig) // Close the synced realm when you're done copying syncRealm.close() // Open the new local realm val localRealm = Realm.open(localConfig) // Copied Frog object is available in the new realm val frog = localRealm.query<Frog>().find().first() Log.v("Copied Frog: ${frog.name}") localRealm.close() }
您还可以在复制的域配置中加入新的加密密钥,或从新配置中删除加密密钥。
例子
将数据从未加密复制到加密 Realm
runBlocking { // Create the unencrypted realm val unencryptedConfig = RealmConfiguration.Builder(setOf(Frog::class)) .name("unencrypted.realm") .build() // Open the realm and add data to it val unencryptedRealm = Realm.open(unencryptedConfig) unencryptedRealm.write { this.copyToRealm(Frog().apply { name = "Kermit" }) } // ... Generate encryption key ... // Create the encrypted realm val encryptedConfig = RealmConfiguration.Builder(setOf(Frog::class)) .name("encrypted.realm") .encryptionKey(encryptionKey) .build() // Copy data from `unencryptedRealm` to the new realm // Data is encrypted as part of the copy process unencryptedRealm.writeCopyTo(encryptedConfig) // Close the original realm when you're done copying unencryptedRealm.close() // Open the new encrypted realm val encryptedRealm = Realm.open(encryptedConfig) // Copied Frog object is available in the new realm val frog = encryptedRealm.query<Frog>().find().first() Log.v("Copied Frog: ${frog.name}") encryptedRealm.close() }
例子
将数据从内存中复制到本地Realm
runBlocking { // Create the in-memory realm val inMemoryConfig = RealmConfiguration.Builder(setOf(Frog::class)) .name("inMemory.realm") .inMemory() .build() // Open the realm and add data to it val inMemoryRealm = Realm.open(inMemoryConfig) inMemoryRealm.write { this.copyToRealm(Frog().apply { name = "Kermit" }) } // Create the local realm val localConfig = RealmConfiguration.Builder(setOf(Frog::class)) .name("local.realm") .build() // Copy data from `inMemoryRealm` to the new realm inMemoryRealm.writeCopyTo(localConfig) // Close the original realm when you're done copying inMemoryRealm.close() // Open the new local realm val localRealm = Realm.open(localConfig) // Copied Frog object is available in the new realm val frog = localRealm.query<Frog>().find().first() Log.v("Copied Frog: ${frog.name}") localRealm.close() }