强大的ORM之Realm基础使用总结

来源:互联网 发布:大连知你创业基地 编辑:程序博客网 时间:2024/06/02 11:41

Realm简单介绍

Realm 专为移动应用而生, 高效, 快速, 轻量.

  1. 表之间的关联不用我们自己管, 不用像 GreenDao 需要自己另外在创建外键关联. 与之相比真是省事不少.
  2. 支持阻塞式的同步操作和非阻塞式的异步操作. 官方说 Realm 是非常快的, 在 UI 线程执行完全不会造成性能问题, 但是当数据量非常大的时候, 可以选择使用异步操作.
  3. 支持RxJava, 不过目前支持的是 Rxjava 1.x 版本.
  4. 完美全面的文档支持. 相比 GreenDao简单少的可伶的文档, Realm 简直堪称完美, 这是我最终选择 Realm 的原因.

看下具体使用吧

PS 在具体使用前, 我还是想吐槽下当下国内的Android技术博客环境. 我想大家应该是跟我有一样的感受, 有时搜索下一个问题, 出现的相关技术博客倒真是不少. 但是一看发现, 绝大部分很水, 相互抄袭成风, 不知道这样的 “博客” 写出来有很么意义? 做技术的, 写博客是一件很好的习惯(虽然我开发了这几年了, 还是现在决定好好坚持写博客), 能够将自己学会的技术很好的总结记录, 不仅方便自己日后查阅, 也可以惠及同行其他哥们, 节约下时间, 更快的成长. 但是目前国内的这种互相抄袭的风气实在让人无法忍受, 对自己写出来的东西太不负责任! 虽然到目前为止, 才写了一两篇博客, 但我能拍着胸脯保证, 绝对不是抄袭, 绝对是我在开发中实际用的了, 即使是参考了别人文章, 我也会去验证, 也会给出参考文章链接! 我只想记录我的技术成长, 如果同时能帮助他人,那当然是更好了!

1. 根据官网, 配置好环境

(1) 在 project 的 build.gradle 中 dependencies 添加如下:

classpath "io.realm:realm-gradle-plugin:3.1.3"(3.1.3 是我在使用时的最新版本)  

(2) 在 module 的 build.gradle 中最最顶部添加如下:

apply plugin: 'realm-android'

2. 配置好环境就可以体验了, 来一波 CRUD 吧

(1) 初始化 Realm, 官方建议我们 Realm 只要初始化一次即可, 在 Application 的 onCreate() 方法中:

public class MyApp extends Application {    @Override    public void onCreate() {        super.onCreate();        Realm.init(this);        RealmConfiguration configuration = new RealmConfiguration                .Builder()                .name("hjm.realm")                .schemaVersion(3)   //升级数据库就加1                .migration(new CustomeMigration())                .build();        Realm.setDefaultConfiguration(configuration);    }}
其中:
name 指定数据库名称, 一般以 .realm 结尾, 如果不设置这一项, 那么默认是 default.realm;
schemaVersion 指定数据库版本号, 如果不设置, 默认是1. 但是当数据看要升级时必须设置并增长
migration 是在数据库变更时执行的操作. 如果要对表结构更改, 则必须设置这一项并在 Migration 中处理(一会儿会重点讲)
注意: 如果只是配置 Realm.init(this) 也是可以的, 并且这个配置的内部配置了默认的DefaultConfiguration. 但是当我们需要数据库更改表结构时, 默认是的配置是不行的, 需要我们加上上述的配置才行.

(2) 开始使用

在 Activity 中的布局就不贴了, 直接看关键代码. 先获取 Realm 对象

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);        mRealm = Realm.getDefaultInstance();    }

(2.1) add 操作

//添加    private void add() {        //同步添加        mRealm.executeTransaction(new Realm.Transaction() {            @Override            public void execute(Realm realm) {                Person person = realm.createObject(Person.class);                person.setName("小明"+i);                person.setAge(10+i);                for (int i1 = 0; i1 < 2; i1++) {                    Student student = realm.createObject(Student.class);                    student.setName("小红");                    student.setGrade(i);                    person.getStudentList().add(student);                }                i++;            }        });        //异步添加        mRealm.executeTransactionAsync(new Realm.Transaction() {            @Override            public void execute(Realm realm) {                Person person = realm.createObject(Person.class);                person.setAge(20);                person.setName("异步");            }        }, new Realm.Transaction.OnSuccess() {            @Override            public void onSuccess() {                Log.e(TAG, "异步添加 onSuccess: ");            }        });    }

说明:

可以看到直接用 mRealm 执行一个事务, 在 execute() 回调中处理添加的操作, 看起来有没有很熟悉的感觉, 如果你用过 RxJava 的话, 应该很有这种感觉吧, 哈哈~~. 当然了你也可以自己创建 Transaction 并 commit, 但是那样有点麻烦啊, 既然已经给你封装好了, 你还去写那些 begin Transaction 和commit Transaction 干嘛呢.

可以看到有两个添加操作, 第一个是同步的, 第二个是异步的. 对于异步的操作,都提供了success 和 fail 的回调, 方便我们处理. 官方说Realm 很快, 在UI线程执行完全没有问题的, 但是个人建议, 如果数据量很大, 还是用异步的吧.

(2.2) delete 操作

private void delete() {        //异步删除所有记录        mRealm.executeTransactionAsync(new Realm.Transaction() {            @Override            public void execute(Realm realm) {                realm.deleteAll();            }        }, new Realm.Transaction.OnSuccess() {            @Override            public void onSuccess() {                Log.e(TAG, "删除成功: ");            }        }, new Realm.Transaction.OnError() {            @Override            public void onError(Throwable error) {                Log.e(TAG, "删除失败: ");            }        });        //同步删除年龄在10-15之间的所有记录        final RealmResults<Person> results = mRealm.where(Person.class)                                                   .between("age", 10, 15)                                                   .findAll();        Log.e(TAG, "年龄在10-15之间的记录size: "+results.size());        mRealm.executeTransaction(new Realm.Transaction() {            @Override            public void execute(Realm realm) {                results.deleteAllFromRealm();            }        });    }

(2.3) update 操作

private void update() {        //将age在10-15的修改为age=1        final RealmResults<Person> age = mRealm.where(Person.class)                                               .between("age", 10, 15)                                               .findAll();        mRealm.executeTransaction(new Realm.Transaction() {            @Override            public void execute(Realm realm) {                for (Person person : age) {                    person.setAge(1);                }            }        });    }

(2.4) query 操作

private void query() {        //查询age在10-15之间的记录        RealmResults<Person> age = mRealm.where(Person.class)                                        .between("age", 11, 15)                                        .findAll();        Log.e(TAG, "age 在10-15之间: "+age.size());        //每个记录对应的studentList 和 animalList        for (Person person : age) {            RealmList<Student> studentList = person.getStudentList();            Log.e(TAG, "studentList.size: "+studentList.size());            RealmList<Animal> animalList = person.getAnimalList();            Log.e(TAG, "animalList.size: "+animalList.size());        }        //异步查询        RealmResults<Person> realmResults = mRealm.where(Person.class)                                              .equalTo("age", 11)//age = 11                                              .or()                                              .greaterThan("age",20)//age > 20                                              .findAllAsync();        realmResults.addChangeListener(new RealmChangeListener<RealmResults<Person>>() {            @Override            public void onChange(RealmResults<Person> element) {                Log.e(TAG, "onChange: "+element.size());            }        });    }

说明:

query 操作主要是各种查询操作符的使用了, 可以说 Realm 提供了很多使用的操作符, 比如 or, equals, greaterThan 等等, 还有算术运算符average 求平均数, 建议大家去好好看看官方文档, 我写的这篇文章也是看官方文档来写的, 当然还有在 githup 上的 sample, 也是学习的资料.

注意: 不知道大家有没有发现, 在add, delete, update 操作时都是执行在 Transaction 中的, 唯独 query 是没有. 是的, 这就是需要注意的地方. add, delete, update 这三个操作时必须执行在 Transaction 中的, 否则会抛出异常.

3. 表之间的一对一, 一对多关系

可以说, Realm 爽的地方, 一点就是咱们不用管去关联表之间的关系, 贴一下我的 Person 这个 bean 你就知道了

public class Person extends RealmObject{    private String name;    private int age;    private RealmList<Student> studentList;    private RealmList<Animal> animalList;    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 RealmList<Student> getStudentList() {        return studentList;    }    public void setStudentList(RealmList<Student> studentList) {        this.studentList = studentList;    }    public RealmList<Animal> getAnimalList() {        return animalList;    }    public void setAnimalList(RealmList<Animal> animalList) {        this.animalList = animalList;    }}

就像平常创建 bean 一样, 不用像 GreenDao 一样去手动创建外键关联

4. 数据库升级, 表结构变化

开发时创建表时, 有时会在后期在表中增加新字段或者删除字段, 这就涉及到表结构的变化了, 这时需要对数据库进行升级才能完成这些操作. 在 Realm 中表结构的变化相对于 GreenDao 来说会麻烦点, 在 GreenDao 中要增加字段或者删除字段就直接加或删,然后 make project 就行了, 因为他是在通过注解在编译期生成代码的. 但是咱们的 Realm 就需要我们自己处理字段的增加和删除了:

(4.1) 在配置时就要设置好 schemaVersion 和 migration.

schemaVersion 默认从0开始, 当需要升级数据库时每次增加1即可
migration 当数据库升级时会执行这个逻辑,可以做数据库升级的具体操作,主要就是我们自己要去实现 Migration, 其实很简单, 如下
/** * Created by hjm on 2017/4/26 14:17. * 当数据库变化时执行: 比如表结构变化了, 创建了新表等 */public class CustomeMigration implements RealmMigration {    private static final String TAG = CustomeMigration.class.getSimpleName();    @Override    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {        RealmSchema schema = realm.getSchema();        Log.e(TAG, "oldVersion: "+oldVersion+" ; newVersion: "+newVersion);        //升级到版本2时, 在 Person 中增加了 Student类型的RealmList        if (newVersion == 2){            RealmObjectSchema personSchema = schema.get("Person");            RealmObjectSchema studentSchema = schema.create("Student");            studentSchema.addField("grade", int.class);            studentSchema.addField("name", String.class);            personSchema.addRealmListField("studentList", studentSchema);        }    }}

套路是固定的, 新创建一个 Student 类型的 RealmObjectSchema, 然后创建 Student 中的字段,然后把 Student 类型的 RealmList 添加进 Person 中.这些在官方文档和 sample 中都有详细的介绍.

OK, 就这些基本用法, 还有其他用法, 强烈建议大家看文档, 官方文档和 sample 才是最权威的. 虽然文档都是英文的, 但挺简单, 大家要耐心看. 有任何问题欢迎大家留言谈论.

0 0
原创粉丝点击