同步查询
- Realm 支持以下查询条件:
-
between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
equalTo() 和 notEqualTo()
contains()、beginsWith() 和 endsWith()
isNull() 和 isNotNull()
isEmpty() 和 isNotEmpty() - 修饰符
字符串查询条件可以通过使用 Case.INSENSITIVE 修饰符来忽略字母 A-Z 和 a-z 的大小写。 - 逻辑运算符
每个查询条件都会被被隐式地被逻辑和(&)组合在一起,而逻辑或(or)需要显式地去执行 or()。
将查询条件组合在一起,使用 beginGroup()(相当于左括号)和 endGroup()(相当于右括号): -
RealmResults<User> r = realm.where(User.class) .greaterThan("id", 10) //这里是逻辑和 .beginGroup() .equalTo("name", "Peter") .or()//这里是逻辑或 .contains("name", "Jo") .endGroup() .findAll();
此外,也可以用 not() 否定一个条件。该 not() 运算符可以与 beginGroup()/endGroup() 一起使用来否定子条件。
- 排序
当你执行完查询获得结果后,可以对它进行排序: -
RealmResults<User> result = realm.where(User.class).findAll(); result = result.sort("age"); // Sort ascending result = result.sort("age", Sort.DESCENDING);
- 查询例子:
-
RealmQuery<User> query = realm.where(User.class); query.equalTo("name", "John"); query.or().equalTo("name", "Peter"); RealmResults<User> result1 = query.findAll();//查询符合条件的所有对象 RealmResults<User> result2 = realm.where(User.class) .equalTo("name", "John") .or() .equalTo("name", "Peter") .findAll();//查询符合条件的所有对象 User user=realm.where(User.class).equalTo("id","1").findFirst();//查询id为1的对象 RealmQuery<User> query=realm.where(User.class); RealmResults<User> resultList=query.findAllSorted("id", Sort.DESCENDING);//查询所有 结果倒序排列
异步查询
Realm支持在后台线程进行查询。如果需要进行非常复杂的查询或者在大量数据中进行查询,那么就应该使用异步查询。异步查询调用很简单,就是在同步方法的后面加Async就可以使用了。
示例:查找名字为 “John” 或者 “Peter” 的用户。
创建异步查询RealmResults<User> result = realm.where(User.class) .equalTo("name", "John") .or() .equalTo("name", "Peter") .findAllAsync();
请注意,这里的调用并不会阻塞,而是立即返回一个 RealmResults。这很类似于标准 Java 中 Future 的概念。查询将会在后台线程中被执行,当其完成时,之前返回的 RealmResults 实例会被更新。
如果你希望当查询完成、RealmResults 被更新时获得通知,你可以注册一个 RealmChangeListener。这个监听器会在 RealmResults 被更新时被调用(通常是在事务被提交后)。
注册回调private RealmChangeListener callback = new RealmChangeListener<RealmResults<User>>() { @Override public void onChange(RealmResults<User> results) { // called once the query complete and on every update } }; public void onStart() { RealmResults<User> result = realm.where(User.class).findAllAsync(); result.addChangeListener(callback); }
请在退出 Activity 或者 Fragment 时移除监听器的注册以避免内存泄漏。
public void onStop () { result.removeChangeListener(callback); //移除指定的监听器 result.removeChangeListeners(); // 移除所有的监听器 }
事务
在任何时间都可以对对象进行访问和查询(读取事务是隐式的)。 所有的写操作(添加、修改和删除对象),必须包含在写入事务(transaction)中。写入事务可以提交或取消。在提交期间,所有更改都将被写入磁盘,并且,只有当所有更改可以被持久化时,提交才会成功。通过取消一个写入事务,所有更改将被丢弃。使用写入事务,会确保你的数据的一致性。
- 事务
-
Realm realm = Realm.getDefaultInstance();//获取Realm单例 realm.beginTransaction();//开始一个事务 //... 对数据库的操作 realm.commitTransaction();//提交事务 realm.cancelTransaction();//取消事务
请注意,写入事务之间会互相阻塞,如果一个写入事务正在进行,那么其他的线程的写入事务就会阻塞它们所在的线程。同时在 U I线程和后台线程使用写入事务有可能导致 ANR 问题。可以使用 异步事务(async transactions)以避免阻塞 UI 线程。
- 事务执行块
除手动调用 realm.beginTransaction()、realm.commitTransaction() 和 realm.cancelTransaction() 之外你可以使用 realm.executeTransaction() 方法,它会自动处理写入事物的开始和提交,并在错误发生时取消写入事物。 -
realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { User user = realm.createObject(User.class); user.setName("John"); user.setEmail("john@corporation.com"); } });
- 异步事务
事务会相互阻塞其所在的线程,在后台线程中开启事务进行写入操作可以有效避免 UI 线程被阻塞。通过使用异步事务,Realm 会在后台线程中进行写入操作,并在事务完成时将结果传回调用线程。 -
在UI线程中调用,有Looper对象,将异步线程的结果通过handler回调到UI线程,也就是OnSuccess,OnError回调函数会在事务成功或者失败时在UI线程执行。。
realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { User user = bgRealm.createObject(User.class); user.setName("John"); user.setEmail("john@corporation.com"); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // Transaction was a success. } }, new Realm.Transaction.OnError() { @Override public void onError(Throwable error) { // Transaction failed and was automatically canceled. } });
在子线程中调用,没有Looper对象,在非 Looper 线程中只有空(null)回调函数被允许使用:
RealmAsyncTask transaction = realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { User user = bgRealm.createObject(User.class); user.setName("John"); user.setEmail("john@corporation.com"); } }, null,null);
异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。
public void onStop () { if (transaction != null && !transaction.isCancelled()) { transaction.cancel(); } }
删除
删除RealmObject分两种方式,一种是继承RealmObject的对象实例,一种是实现RealmModel接口的对象实例。
删除可以从查询结果中删除数据:final RealmResults<Dog> results = realm.where(Dog.class).findAll();//查询数据 realm.executeTransaction(new Realm.Transaction() {//当对数据库进行改变数据时,必须在一个事务中 @Override public void execute(Realm realm) { results.deleteFirstFromRealm();//删除数组的首个元素 results.deleteLastFromRealm();//删除数组的最后一个元素 Dog dog = results.get(5); dog.deleteFromRealm();//Dog类继承RealmObject类 删除指定下标的元素 RealmObject.deleteFromRealm(dog );//Dog类实现RealmModel接口 删除指定下标的元素 results.deleteAllFromRealm();//清空Dog表 } });
插入
插入数据必须开启一个事务,然后创建一个RealmObject的对象实例,并赋值进行初始化,然后提交事务就可以插入到数据库中了。
User user=new User(); user.setId("1"); user.setName("Jason"); user.setIntro("Hello World!"); Realm realm = Realm.getDefaultInstance(); //方式一 使用beginTransaction开启事务 realm.beginTransaction(); User reslmUser=realm.copyToRealm(user);//reslmUser指向了数据库中的数据 对该对象的修改都会保存到数据库 realm.commitTransaction(); realm.executeTransaction(new Realm.Transaction() {//方式二 使用executeTransaction 会在execute执行完自动提交或发生错误取消 @Override public void execute(Realm realm) { User user2=realm.createObject(User.class,"1");//参数一 表名 参数二 主键值 user2.setName("Jason"); user2.setIntro("Hello World!"); } });
更新
更新操作跟插入操作差不多,前提是必须获取到RealmObject数据,可以进行查询数据获取RealmResults或者RealmObject后再进行更新操作。更新也必须开启一个事务,然后在事务中对RealmObject对象进行修改字段变量值就可以了,跟插入操作类似。
final User user=realm.where(User.class).equalTo("id","1").findFirst();//先查询 获取RealmObject对象 realm.executeTransaction(new Realm.Transaction() {//开启事务 @Override public void execute(Realm realm) { user.setIntro("更新Intro");//修改数据库中所指向的对象的值 execute执行完会自动提交 user.setName("king"); } });
支持JSON
可以直接将 JSON 对象添加到 Realm 中,这些 JSON 对象可以是一个 String、一个 JSONObject 或者是一个 InputStream。Realm 会忽略 JSON 中存在但未定义在 Realm 模型类里的字段。单独对象可以通过 Realm.createObjectFromJson() 添加。对象列表可以通过 Realm.createAllFromJson() 添加。
// A RealmObject that represents a city public class City extends RealmObject { private String city; private int id; // getters and setters left out ... } // Insert from a string realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { realm.createObjectFromJson(City.class, "{ city: \"Copenhagen\", id: 1 }"); } }); // Insert multiple items using an InputStream realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { try { InputStream is = new FileInputStream(new File("path_to_file")); realm.createAllFromJson(City.class, is); } catch (IOException e) { throw new RuntimeException(); } } });
Realm 解析 JSON 时遵循如下规则: * 使用包含空值(null)的 JSON 创建对象: * 对于非必须(可为空值的属性),设置其值为 null; * 对于必须(不可为空值的属性),抛出异常; * 使用包含空值(null)的 JSON 更新对象: * 对于非必须(可为空值的属性),设置其值为 null; * 对于必须(不可为空值的属性),抛出异常; * 使用不包含对应属性的 JSON: * 该属性保持不变
监听数据改变
Realm数据库支持在Realm实例,RealmObject 和 RealmResults 实例上添加监听器。可以通过这样的方式来监视对象和查询结果的改变,在监听对象的引用对象改变时监听器被触发。另外,当监听回调函数被调用时,相应的数据已经被更新,你不需要去做刷新操作。
public class MyActivity extends Activity { private Realm realm; private RealmChangeListener puppiesListener; private RealmChangeListener dogListener; private RealmResults<Dog> puppies; private Dog dog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); realm = Realm.getDefaultInstance(); puppiesListener = new RealmChangeListener<RealmResults<Dog>>() { @Override public void onChange(RealmResults<Dog> puppies) { // ... do something with the updated puppies instance }}; // Find all the puppies puppies = realm.where(Dog.class).lessThanOrEqualTo("age", 2).findAll(); puppies.addChangeListener(puppiesListener); dogListener = new RealmChangeListener<Dog>() { @Override public void onChange(Dog dog) { // ... do something with the updated Dog instance }}; dog = realm.where(Dog.class).equals("name", "Fido").findFirst(); dog.addChangeListener(dogListener); } @Override protected void onDestroy() { super.onDestroy(); // Remove the listeners puppies.removeChangeListener(puppiesListener); dog.removeChangeListener(dogListener); // Close the Realm instance. realm.close(); } }
Intent传递数据
Realm并不支持直接通过intent传递RealmObject对象,官方建议只传递RealmObject 的标识符,可以是主键或某个字段。
例如RealmObject对象实例person拥有一个主键id,可以通过intent的bundle来传递这个主键的值。// Assuming we had a person class with a @PrimaryKey on the 'id' field ... Intent intent = new Intent(getActivity(), ReceivingService.class); intent.putExtra("person_id", person.getId()); getActivity().startService(intent);
在接受方(Activty、Service、IntentService、BroadcastReceiver 及其它)从 bundle 中解析出这个主键然后打开 Realm 查询得到这个 RealmObject。
// in onCreate(), onHandleIntent(), etc. String personId = intent.getStringExtra("person_id"); Realm realm = Realm.getDefaultInstance(); Person person = realm.where(Person.class).equalTo("id", personId).findFirst(); // do something with the person ... realm.close();
因为Realm查询速度够快了,所以再查询一次的时间消耗还是微乎其微的。
参考资料:Realm文档:
https://realm.io/cn/docs/java/latest/