文章目录
Realm(Java)数据库使用文档(目录)
Realm是移动设备数据库的实例。 Realm可以是本地的或同步的。同步的Realm使用Realm Object Server透明地将其内容与其他设备同步。 当您的App像本地文件一样继续使用同步的Realm时,该Realm中的数据可能会被具有该Realm写入权限的任何设备更新。 实际上,您的App可以与本地或同步的任何Realm相同的方式工作。
您是否要使用Realm 移动设备同步所有Realm数据库?
所有与同步相关的文档已移至我们的平台文档
有关Realm的更详细讨论,请阅读 Realm数据模型。
2.1 初始化
通过实例化新的Realm
对象来打开Realm。 我们已经在示例中看到了这种用法:
// 初始化Realm
Realm.init(context);
// 获取此线程的Realm实例
Realm realm = Realm.getDefaultInstance();
getDefaultInstance()
方法使用默认的RealmConfiguration
配置实例化Realm。
2.1.1 Realm配置
要控制Realm的创建方式,请使用RealmConfiguration对象。 Realm最基本配置为:
RealmConfiguration config = new RealmConfiguration.Builder().build();
该配置(无选项)使用位于Context.getFilesDir
中的Realm文件default.realm
。 要使用其他配置,您需要创建一个新的RealmConfiguration
对象:
// 使用构建器模式创建RealmConfiguration。
// Realm文件将位于Context.getFilesDir()中,名称为“ myrealm.realm”
RealmConfiguration config = new RealmConfiguration.Builder()
.name("myrealm.realm")
.encryptionKey(getKey())
.schemaVersion(42)
.modules(new MySchemaModule())
.migration(new MyMigration())
.build();
// 使用配置
Realm realm = Realm.getInstance(config);
您可以具有多个RealmConfiguration对象,因此可以独立控制每个Realm的版本,架构和位置。
RealmConfiguration myConfig = new RealmConfiguration.Builder()
.name("myrealm.realm")
.schemaVersion(2)
.modules(new MyCustomSchema())
.build();
RealmConfiguration otherConfig = new RealmConfiguration.Builder()
.name("otherrealm.realm")
.schemaVersion(5)
.modules(new MyOtherSchema())
.build();
Realm myRealm = Realm.getInstance(myConfig);
Realm otherRealm = Realm.getInstance(otherConfig);
通过使用Realm.getPath
获取领域的绝对路径。
重要的是要注意,Realm
实例是线程单例,这意味着静态构造函数将响应来自给定线程的所有调用而返回相同的实例。
2.2.2 默认Realm
可以将RealmConfiguration
保存为默认配置。 在自定义Application类中设置默认配置将使其在整个App中可用。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 默认的Realm文件在Context.getFilesDir();中为“ default.realm”;
// 我们将其更改为“ myrealm.realm”
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
}
}
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Realm realm = Realm.getDefaultInstance(); // 打开“ myrealm.realm”
try {
// ... Do something ...
} finally {
realm.close();
}
}
}
2.2 打开一个同步的Realm
您是否要使用Realm移动设备同步所有Realm数据库?
所有与同步相关的文档已移至我们的平台文档
2.3 只读Realms
只读仅在当前进程中强制执行。 其他进程或设备仍然有可能写入只读Realms。 同样,针对只读Realms的任何写事务都会抛出IllegalStateException。这包括尝试编写模式,因此最初必须由其他来源提供。
在您的应用中附带准备好的Realm文件有时会很有用-您可能希望将一些共享数据与您的应用捆绑在一起。 在很多情况下,您都不希望意外修改该Realm,因为数据纯粹是只读的。您可以通过在资产中捆绑Realm文件并使用只读配置来做到这一点:
RealmConfiguration config = new RealmConfiguration.Builder()
.assetFile("my.realm")
.readOnly()
// 可选的,但是建议创建一个模块来描述捆绑文件中的类。 否则,如果您的App包含文件中找不到的其他类,则由于无法以只读模式更新架构,因此在打开Realm时它将崩溃。
.modules(new BundledRealmModule())
.build();
2.4 内存Realms
使用inMemory
配置,您可以创建一个完全在内存中运行而不会持久化到磁盘的Realm。
RealmConfiguration myConfig = new RealmConfiguration.Builder()
.name("myrealm.realm")
.inMemory()
.build();
如果内存不足,内存中的 Realm可能仍会使用磁盘空间,但是由内存中的 Realm创建的所有文件将在关闭Realm时被删除。 不允许使用与永久性Realm相同的名称创建内存中Realm-名称仍然必须唯一。
当所有具有特定名称的内存Realm实例超出范围而没有引用时,会释放所有Realm的数据。 要在整个应用执行过程中保持内存中的“活动状态”,请保留对其的引用。
2.5 动态Realms——DynamicRealm
在使用常规Realm
时,使用RealmObject
子类定义模型类。 关于类型安全性,这有很多好处。 但是有时,这些类型只有在运行时才可用,例如,在迁移期间或使用CSV文件等基于字符串的数据时,就可以用DynamicRealm!
DynamicRealm是常规Realm的一种变体,它可以使用Realm数据而无需使用RealmObject
子类。 而是直接使用字符串而不是类来完成所有访问。
打开DynamicRealm使用与常规Realm相同的配置,但是DynamicRealm会忽略任何已配置的架构,迁移和架构版本。
RealmConfiguration realmConfig = new RealmConfiguration.Builder().build();
DynamicRealm realm = DynamicRealm.getInstance(realmConfig);
// 在DynamicRealm中,所有对象都是DynamicRealmObjects
realm.beginTransaction();
DynamicRealmObject person = realm.createObject("Person");
realm.commitTransaction();
// 使用字符串访问所有字段
String name = person.getString("name");
int age = person.getInt("age");
// 基础架构仍然存在,因此访问不存在的字段将引发异常
person.getString("I don't exist");
// 查询仍然可以正常工作
RealmResults<DynamicRealmObject> persons = realm.where("Person")
.equalTo("name", "John")
.findAll();
DynamicRealm
以灵活性和性能为代价获得灵活性。 通常,您应该使用常规Realm。 仅在需要这种灵活性时才使用DynamicRealm。
2.6 关闭Realms
Realm
实现Closeable
来处理本机内存的重新分配和文件描述符,因此在使用完Realm实例后,请务必关闭它们。
Realm
实例是引用计数的-如果您在线程中两次调用getInstance
,则也需要两次调用close
。 这使您可以实现Runnable
类,而不必担心哪个线程将执行它们:只需以getInstance
开头并以close
结束即可。
对于UI线程,最简单的方法是在拥有组件的onDestroy()
方法中执行realm.close
。 如果您需要创建UI以外的Looper
线程,则可以使用以下模式:
public class MyThread extends Thread {
private Realm realm;
@Override
public void run() {
Looper.prepare();
realm = Realm.getDefaultInstance();
try {
//... 使用Realm实例设置处理程序 ...
Looper.loop();
} finally {
realm.close();
}
}
}
对于AsyncTask
,这是一个很好的模式:
protected Void doInBackground(Void... params) {
Realm realm = Realm.getDefaultInstance();
try {
// ... Use the Realm instance ...
} finally {
realm.close();
}
return null;
}
如果你使用Thread
或Runnable
用于短期任务:
// Run a non-Looper thread with a Realm instance.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Realm realm = Realm.getDefaultInstance();
try {
// ... Use the Realm instance ...
} finally {
realm.close();
}
}
});
thread.start();
如果您正在使用minSdkVersion> = 19
而且Java> = 7
的应用程序,则可以使用try-with-resources:
try (Realm realm = Realm.getDefaultInstance()) {
// 无需手动关闭Realm实例
}
2.7 自动刷新
如果从与Looper关联的线程获取Realm实例,则Realm实例将具有自动刷新功能。 (Android的UI线程是Looper。)这意味着Realm实例将定期更新为最新版本。 这使您可以毫不费力地用最新内容不断更新UI!
如果您从未附加Looper
的线程获取Realm实例,则在调用waitForChange
方法之前,不会更新该实例中的对象。 保留旧版本的数据在内存和磁盘空间方面都很昂贵,并且随着保留的版本和最新版本之间的版本数量增加,成本也会随之增加。 这就是为什么在线程中完成Realm实例后立即关闭它很重要的原因。
如果要检查您的Realm实例是否已激活自动刷新,请使用isAutoRefresh
方法。