Android realm数据库使用笔记

来源:互联网 发布:java 清华 pdf 编辑:程序博客网 时间:2024/05/02 06:17
1.realm有两种申明模型方式:
(1)直接继承于 RealmObject  
public class Dog extends RealmObject {
    public String name;
    public int age;
}
(2)通过实现 RealmModel 接口并添加 @RealmClass 修饰符来声明
@RealmClass
public class User implements RealmModel {


}

注:

经验证,现在realm只支持直接继承RealmObject的模型存储,间接继承的不能存储。

经验证,realm只支持直接继承RealmObject或直接实现RealmModel 接口两者中的一种,同时存在则不可以。

经验证,realm可以在继承RealmObject的时候实现RealmModel以外的其余的接口。
经验证,realm不支持继承别的类再去实现RealmModel接口。


2.请注意,写入事务之间会互相阻塞,如果一个写入事务正在进行,那么其他的线程的写入事务就会阻塞它们所在的线程。同时在 U I线程和后台线程使用写入事务有可能导致 ANR 问题。可以使用 异步事务(async transactions)以避免阻塞 UI 线程。
异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。

在项目里尽量使用异步事务,尽管大多数时候提交事务都很快,但是要避免极端情况带来的阻塞。


3.设置一个类型为 RealmList 的属性为空值(null)会清空该列表,即列表长度变为 0。但并不会删除列表中的任何 RealmObject。RealmList 的获取器(getter)永不会返回 null。其返回对象永远是一个 RealmList 实例,但其长度有可能为0。



4.Realm 的写操作针对的是整个字符串或 byte 数组属性而非该属性中的单独元素。假设你需要修改某 byte 数组中的第五个字符,你需要:
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        bytes[] bytes = realmObject.binary;
        bytes[4] = 'a';
        realm.binary = bytes;
    }
});


5.所有的 Realm 集合都会自动更新。它们总会被更新到最新的数据。这在大多数情况下是符合预期的。但是在遍历并且同时修改集合元素时,自动更新的特性会给你带来麻烦。例如:
RealmResults<Person> guests = realm.where(Person.class).equalTo("invited", false).findAll();
realm.beginTransaction();
for (int i = 0; guests.size(); i++) {
    guests.get(i).setInvited(true);
}
realm.commitTransaction();
这段代码预期通过一个简单循环来邀请所有的 Guest 对象。因为 RealmResults 在每次循环都会被更新,你会发现最终的运行结果是只有一半的 Guest 对象收到了邀请。当 Guest 对象收到邀请以后,它会被立即从集合中移除,因为它不再满足查询条件,集合的大小在此刻发生了改变,所以当 i 增加时,循环会错过一个集合元素。
你可以通过使用集合数据的 快照 来解决这个问题。集合快照保证其中的元素及其顺序不会改变,即使在元素被修改甚至删除的情况下。
Realm 集合的迭代子(Iterator)会自动使用快照。你也可以通过 RealmResults 和 RealmList 的 createSnapshot() 方法来创建一个快照。
RealmResults<Person> guests = realm.where(Person.class).equalTo("invited", false).findAll();

// Use an iterator to invite all guests
realm.beginTransaction();
for (Person guest : guests) {
guest.setInvited(true);
}
realm.commitTransaction();


// Use a snapshot to invite all guests
realm.beginTransaction();
OrderedRealmCollectionSnapshot<Person> guestsSnapshot = guests.createSnapshot();
for (int i = 0; guestsSnapshot.size(); i++) {
guestsSnapshot.get(i).setInvited(true);
}
realm.commitTransaction();


6.当查询没有任何匹配时,返回的 RealmResults 对象将不会为 null,取而代之的是它的 size() 方法将返回 0。


7.删除某一项时:
 users.get(0).deleteFromRealm(); // indirectly delete object   不安全 可能导致已删除的数据还在被使用
users.deleteFromRealm(0); // Delete and remove object directly  安全


8.集合通知与 Realm 通知不同,它会包含针对那些集合数据改变的信息。这些信息会指明从上次通知到达以来,集合中的插入、删除以及改变的元素索引。

对于异步查询(findAllAsync())来说通知第一次到达时改变集合为空,表明了这是异步查询完成后的第一次通知,之后的通知则包含相应的集合改变信息。


9.对象通知(Object notifications)
你可以为某个 Realm 对象注册监听器以获得针对对象属性修改的细粒度通知。
只有托管 RealmObject 可以注册监听器。
你可以通过监听器传递的 ObjectChangeSet 来获取对象属性改变的详细信息,包括哪些属性被修改以及该对象已被删除。
在监听对象被删除时 ObjectChangeSet.isDeleted() 会返回 true。
ObjectChangeSet.getChangedFields() 会返回哪些字段有所改变。你也可以通过 ObjectChangeSet.isFieldChanged() 来判断一个指定字段是否改变。


10.防止出现 ANR
一般来说 Realm 的读写是足够快的,甚至在 UI 线程中读写也不是问题。但是,写事务是互相阻塞的,所以为了避免 ANR 的出现,我们建议你在后台线程中执行写操作。参考异步事务获得如何在后台线程进行写入相关的信息。


11.为了避免不必要的 Realm 数据连接的打开和关闭,Realm 内部有一个基于引用计数的缓存。这表示在同一线程内调用 Realm.getDefaultInstance() 多次是基本没有开销的,并且底层资源会在所有实例都关闭的时候才被释放。


12.Realm 对象实例可以是托管(managed)或是非托管(unmanaged)的。
托管对象 是被 Realm 持久化的,会自动更新且被限制在了指定线程。因为它会在 Java 堆上占用更少空间,所以总体上它比非托管对象更轻量。
非托管对象 就和普通的 Java 对象一样。它们没有被持久化且不会自动更新。它们没有线程限制。
托管对象和非托管对象之间可以通过 Realm.copyToRealm() 和 Realm.copyFromRealm() 来相互转换。