使用 Realm 文件 — .NET SDK
域是一设立符合预定义模式的相关对象。 Realm 可以包含多种类型的数据,只要每种类型都存在模式。
每个域将数据存储在单独的域文件中,该文件包含域中每个对象的二进制编码。 您可以跨多个域自动同步 Realm,并设立响应式事件处理程序,以便在每次创建、修改或删除域中的对象时调用函数。
Realm生命周期
每个域实例都会消耗大量资源。 打开和关闭域都是昂贵的操作,但保持域打开也会产生大量资源开销。 为了最大限度地提高应用程序的性能,您应该在任何给定时间最大限度地减少打开 Realm 的数量,并限制使用的打开和关闭操作的次数。
然而,打开一个域并不总是那么昂贵。 如果域已在同一进程或线程中打开,则打开额外的实例所需的资源更少:
如果未在同一进程中打开 Realm,则打开 Realm 的开销很高。
如果 Realm 已在同一进程内的不同线程上打开,则打开 Realm 的成本较低,但仍然很重要。
如果已在同一进程内的同一线程上打开 Realm,则打开该 Realm 只需最少的额外资源。
当您首次打开域时, Realm会执行在域中读取和写入数据所需的内存映射和模式验证。 同一线程上该域的其他实例使用相同的根本的资源。 不同线程上该域的实例使用一些相同的根本的资源。
当一个域的所有连接在一个线程中关闭时, Realm会释放用于连接该域的线程资源。 当进程中与某个域的所有连接都关闭时, Realm会释放用于连接该域的所有资源。
作为最佳实践,我们建议将 Realm 实例生命周期与观察域的视图的生命周期绑定在一起。实例,考虑一个通过RecyclerView
显示RealmResults
数据的Fragment
。您可以:
在
Fragment.onCreateView()
生命周期方法中打开一个包含该视图数据的单个域 。在
Fragment.onDestroyView()
生命周期方法中关闭同一域 。
注意
如果您的域特别大,则在Fragment.onCreateView()
中获取域实例可能会短暂区块渲染。 如果在onCreateView()
中打开您的域会导致性能问题,请考虑改为从Fragment.onStart()
和Fragment.onStop()
管理该域 。
如果多个Fragment
实例需要访问同一数据集,您可以在封闭的Activity
中管理单个 Realm:
在
Activity.onCreate()
生命周期方法中打开域 。在
Activity.onDestroy()
生命周期方法中关闭 Realm。
多进程
您无法从不同进程同时访问权限加密或同步Realm。 但是,本地 Realm 通常可以跨进程运行,因此您可以读取、写入多个 APK 和接收来自多个 APK 的通知。
Realm 模式
Realm 模式是有效对象模式的列表,每个模式定义应用程序可以持久保存的对象类型。 Realm 中的所有对象都必须符合域Realm 模式。
默认情况下,SDK 会自动将项目中从 RealmObject 派生的所有类添加到 Realm 模式中。
客户端应用程序在打开域时提供Realm 模式。 如果域已包含数据,则Realm会验证每个现有对象,以确保为其类型提供了对象模式,并且满足模式中指定的所有约束。
例子
包含图书馆中图书基本数据的域可能会使用如下模式:
[ { "type": "Library", "properties": { "address": "string", "books": "Book[]" } }, { "type": "Book", "primaryKey": "isbn", "properties": { "isbn": "string", "title": "string", "author": "string", "numberOwned": { "type": "int?", "default": 0 }, "numberLoaned": { "type": "int?", "default": 0 } } } ]
同步 Realm
使用Atlas Device Sync的应用可以打开同步域。
使用 Flexible Sync 时,可以通过订阅查询自定义客户端应用程序同步的数据。这些查询在应用程序后端搜索数据,并且 Flexible Sync realm 同步与查询匹配的数据。客户端应用程序只能同步用户具有适当读写权限以访问数据的数据。
当您使用基于分区的同步时,同步的 Realm 表示 Atlas 数据的分区。 每个 Realm 对应于应用数据源中数据的一个子集。 您可以使用应用程序的 分区键 自定义数据 分区 。分区键的唯一值(称为分区值)与各个 Realm 相对应。
在配置Realm规则时,您可以自定义同步 Realm 可以从您的应用程序读取和写入的数据的权限。
有关更多信息,请参阅配置同步Realm - Java SDK。
查找您的Realm文件
Realm将域中每个对象和类型的二进制编码版本存储在单个.realm
文件中。
运行Realm Studio的机器无法直接访问 Android 模拟器使用的文件系统。 您必须先从模拟器下载该文件,然后才能访问权限。
首先,在模拟器上找到该文件的路径:
// Run this on the device to find the path on the emulator Realm realm = Realm.getDefaultInstance(); Log.i("Realm", realm.getPath());
然后,使用 ADB下载文件。 您可以在应用运行时执行此操作。
> adb pull <path>
您还可以使用 ADB 再次上传修改后的文件,但前提是应用未运行。 在应用运行时上传修改后的文件可能会损坏该文件。
> adb push <file> <path>
Realm 文件大小
Realm通常比同等的 SQLite数据库占用更少的磁盘空间。 但是,为了向您提供一致的数据视图, Realm会对域的多个版本进行操作。 如果同时打开某个域的多个版本,则该域文件可能需要额外的磁盘空间。
这些版本占用的空间量取决于每个事务中的更改量。 许多小型事务的开销与少量大型事务相同。
文件大小意外增长通常由以下三个原因之一造成:
您在背景线程上打开一个域 ,却忘记再次将其关闭。 因此, Realm在背景线程上保留了对旧版本数据的引用。 由于Realm会在带有 Looper 的线程上自动将 Realm 更新到最新版本,因此用户界面线程和其他 Looper 线程不存在此问题。
您引用了过多多版本的冻结对象。冻结对象会保留首次冻结对象时存在的 Realm 版本。如果需要冻结大量对象,请考虑使用 Realm.copyFromRealm(),而不是仅保留您需要的数据。
您从域中读取了一些数据。然后,您可以通过长时间运行的操作来区块线程。同时,您在其他线程上多次向域写入。 这会导致Realm创建许多中间版本。 您可以通过以下方式避免这种情况:
批处理写入
避免让域保持打开状态,否则会阻塞背景线程。
限制活动版本的最大数量
您可以在构建RealmConfiguration
时设置maxNumberOfActiveVersions() ,以便在应用程序打开的 Realm 版本超过允许数量时引发IllegalStateException
。 版本是在执行写事务时创建的。
一旦您的应用程序不再使用旧版本的数据, Realm就会自动删除这些数据。 但是, Realm不会释放旧版本数据所使用的空间;相反,该空间用于对域进行新的写入。
压缩 Realm
您可以通过压缩Realm 文件来删除未使用的空间:
手动:调用 compactRealm()
自动:在 Android 应用程序中打开与 Realm 的第一个连接时,指定 compactOnLaunch() 构建器选项
重要
压缩所有生产应用程序
每个生产应用程序都应实施压缩,以定期减小 Realm 文件的大小。
备份和恢复 Realm
Realm 使用 Android 设备上的文件将 Realm 持久保存到磁盘上。要备份 Realm,找到 Realm 文件并将其复制到安全位置。您应该在复制 Realm 之前关闭该 Realm 的所有实例。
或者,也可以使用 realm.writeCopyTo() 将 Realm 的压缩版本写入目标文件。
模块
Realm 模块描述了可以存储在 Realm 中的一组 Realm 对象。默认情况下,Realm 会自动创建一个 Realm 模块,其中包含应用程序中定义的所有 Realm 对象。您可以定义一个 RealmModule,将 Realm 限制为应用程序中定义的类的子集。如果您生成一个使用 Realm 的库,则可以使用 Realm 模块来显式地仅将库中定义的 Realm 对象包含在您的 Realm 中。这样,包含您的库的应用程序也可以使用 Realm,而无需管理与库定义的 Realm 对象的对象名称冲突和迁移。