Realm 数据库笔记(一)

Realm 数据库

ORMlite,greenDao这些框架都是在SQLite的基础上封装的ORM对象关系映射框架,简化了代码操作。
而今天的主角:Realm是一个可以替代SQLite以及ORM Libraries的轻量级数据库。
相比SQLite,Realm更快并且具有很多现代数据库的特性,比如支持JSON,流式api,数据变更通知,以及加密支持,这些都为安卓开发者带来了方便。不多介绍,更详细的介绍参见官网:https://realm.io/


安装

第一步: 在项目的 build.gradle 文件中添加如下 class path 依赖。
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:3.1.1"
    }
}
第二步: 在 app 的 build.gradle 文件中应用 realm-android 插件。
apply plugin: 'realm-android'

使用

Realm 数据模型定义需要继承自 RealmObject 类。

public class User extends RealmObject {

    private String          name;
    private int             age;

    @Ignore
    private int             sessionId;

    // Standard getters & setters generated by your IDE…
    public String getName() { return name; }
    public void   setName(String name) { this.name = name; }
    public int    getAge() { return age; }
    public void   setAge(int age) { this.age = age; }
    public int    getSessionId() { return sessionId; }
    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }
}

RealmModel 接口
除直接继承于 RealmObject 来声明 Realm 数据模型之外,还可以通过实现 RealmModel 接口并添加 @RealmClass 修饰符来声明。

@RealmClass
public class User implements RealmModel {

}
写入

在任何时间都可以对对象进行访问和查询(读取事务是隐式的)。 所有的写操作(添加、修改和删除对象),必须包含在写入事务(transaction)中。写入事务可以提交或取消。在提交期间,所有更改都将被写入磁盘,并且,只有当所有更改可以被持久化时,提交才会成功。通过取消一个写入事务,所有更改将被丢弃。使用写入事务,会确保你的数据的一致性。

写入事务也用于确保线程安全:

// Obtain a Realm instance
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
//... add or update objects here ...
realm.cancelTransaction();
//  ...
realm.commitTransaction();

事务执行块(Transaction blocks)
事务会相互阻塞其所在的线程,在后台线程中开启事务进行写入操作可以有效避免 UI 线程被阻塞。通过使用异步事务,Realm 会在后台线程中进行写入操作,并在事务完成时将结果传回调用线程。OnSuccess 和 OnError 并不是必须重载的,重载了的回调函数会在事务成功或者失败时在被调用发生的线程执行。回调函数是通过 Looper 被执行的,所以在非 Looper 线程中只有空(null)回调函数被允许使用。

//同步
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");
    }
});

//异步
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.
    }
});

//异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。
public void onStop () {
    if (transaction != null && !transaction.isCancelled()) {
        transaction.cancel();
    }
}
快照(Snapshots)

这段代码预期通过一个简单循环来邀请所有的 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();
查询

Realm 中的所有读取(包括查询)操作都是延迟执行的,且数据绝不会被拷贝。

比如查找所有叫做 John 或 Peter 的用户,你可以这么写:

public class User extends RealmObject {

    @PrimaryKey
    private String          name;
    private int             age;

    @Ignore
    private int             sessionId;

    // Standard getters & setters generated by your IDE…
    public String getName() { return name; }
    public void   setName(String name) { this.name = name; }
    public int    getAge() { return age; }
    public void   setAge(int age) { this.age = age; }
    public int    getSessionId() { return sessionId; }
    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }
}

// Build the query looking at all users:
RealmQuery<User> query = realm.where(User.class);

// Add query conditions:
query.equalTo("name", "John");
query.or().equalTo("name", "Peter");

// Execute the query:
RealmResults<User> result1 = query.findAll();

// Or alternatively do the same all at once (the "Fluent interface"):
RealmResults<User> result2 = realm.where(User.class)
                                  .equalTo("name", "John")
                                  .or()
                                  .equalTo("name", "Peter")
                                  .findAll();

查询条件
通过 where() 方法你可以得到一个 RealmQuery 对象并通过该对象创建各种查询条件。

查询的第一个参数是字段名称。假如字段不支持这个查询条件异常会被抛出。

所有数据类型均支持如下查询条件:

equalTo()
notEqualTo()
in() 可以用来匹配一组数据中的某个成员。例如来查询 name 为 ”Jill“、”William” 或者 “Trillian” 的对象,你可以使用 in(“name”, new String[]{“Jill”, “William”, “Trillian”})。in() 支持字符串、二进制数据和数值型字段。

数值型字段,包括 Date 还支持如下这些查询条件:
between()
greaterThan()
lessThan()
greaterThanOrEqualTo()
lessThanOrEqualTo()
字符串类型字段额外支持如下查询条件:
contains()
beginsWith()
endsWith()
like()
示例:

RealmResults<User> r = realm.where(User.class)
                            .greaterThan("age", 10)  //implicit AND
                            .beginGroup()
                                .equalTo("name", "Peter")
                                .or()
                                .contains("name", "Jo")
                            .endGroup()
                            .findAll();

RealmResults<User> r = realm.where(User.class)
                           .not()
                           .beginGroup()
                                .equalTo("name", "Peter")
                                .or()
                                .contains("name", "Jo")
                            .endGroup()
                            .findAll();

RealmResults<User> r = realm.where(User.class)
                           .not()
                           .in("name", new String[]{"Peter", "Jo"})

RealmResults<User> result = realm.where(User.class).findAll();
result = result.sort("age"); // Sort ascending
result = result.sort("age", Sort.DESCENDING);
查询结果的自动更新(Auto-Updating Results)

RealmResults 是对其所包含数据的自动更新视图,这意味着它永远不需要被重新查询获取。数据对象的改变会立刻被反映到相应的查询结果。

final RealmResults<Dog> puppies = realm.where(Dog.class).lessThan("age", 2).findAll();
puppies.size(); // => 0

realm.executeTransaction(new Realm.Transaction() {
    @Override
    void public execute(Realm realm) {
        Dog dog = realm.createObject(Dog.class);
        dog.setName("Fido");
        dog.setAge(1);
    }
});

puppies.addChangeListener(new RealmChangeListener() {
    @Override
    public void onChange(RealmResults<Dog> results) {
      // results and puppies point are both up to date
      results.size(); // => 1
      puppies.size(); // => 1
    }
});

这对所有的 RealmResults 有效 —— 无论是否有过滤条件、是否是链式查询。

RealmResults 的这个特性不仅使得 Realm 快速高效,而且让你的代码更简洁。举例来说,假设你的 Activity 或者 Fragment 依赖于某个查询结果,你可以将相应的 Realm 对象或者 RealmResults 保存为一个属性,你不需要在每次访问时确定其是否被更新 —— Realm 会保证这些。

你可以通过订阅 Realm notifications 来得知 Realm 数据更新了,进而刷新 UI 而不必重新查询获得 RealmResults。

因为查询结果的自动更新特性,请不要依赖于固定的索引(indices)、不变的条目数。

删除
// obtain the results of a query
final RealmResults<Dog> results = realm.where(Dog.class).findAll();

// All changes to data must happen in a transaction
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        // remove single match
        results.deleteFirstFromRealm();
        results.deleteLastFromRealm();

        // remove a single object
        Dog dog = results.get(5);
        dog.deleteFromRealm();

        // Delete all matches
        results.deleteAllFromRealm();
    }
});
异步查询(Asynchronous Queries)
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

public void onStop () {
    result.removeChangeListener(callback); // remove a particular listener
    // or
    result.removeChangeListeners(); // remove all registered listeners
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值