在Android中使用Realm作本地存储

Android平台有很多的orm框架可以对数据作本地存储,比如ormlite、greenDao、SugarORM等等,这些orm框架基本都是基于sqlite的。今天我要介绍的这个数据库Realm,是用来替代sqlite的一种解决方案,它有一套自己的数据库存储引擎,比sqlite更轻量级,拥有更快的速度,最重要的是跨平台,目前已有Java,Objective C,Swift,React-Native,Xamarin这五种实现。
本文是Realm数据库在Android中使用的一个入门级的教程,这里不对Realm与其他的orm框架的优缺点作讨论(这些网上已是一搜一大把)。

本文学习目录
一.环境配置
二.创建实体
三.CRUD(增删改查操作)
四.进阶用法

一.环境配置

  1. 在项目的build文件加上
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        ...
        classpath "io.realm:realm-gradle-plugin:1.2.0"
    }  
  1. 在 app 的 build文件中加入
apply plugin: 'realm-android'

二.创建实体

Realm 支持的字段类型,除了Java提供的基本类型之外,Realm还支持<code>继承了RealmObject 的对象</code>和<code>RealmList<? extends RealmObject></code>

这里为了方便直接使用了示例项目中的对象了。

创建一个User实体

public class User extends RealmObject {
    @PrimaryKey
    private String id;
    private String name;
    private int age;
    private RealmList<User> friends;

    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 String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public RealmList<User> getFriends() {
        return friends;
    }

    public void setFriends(RealmList<User> friends) {
        this.friends = friends;
    }
}

细心的同学已经注意到了,我们上面创建的实体对象继承于RealmObject ,Realm 数据实体定义需要继承自 RealmObject类。

这里需要知道的几点:

  • <code>@PrimaryKey</code>用来标识主键
  • 默认的所有的字段都会被存储
  • 如果某个字段不需要被存储到本地,则需在在这个字段上面加上<code>@Ignore</code>注解

三.CRUD(增删改查操作)

数据库的使用无非上就是增删改查这四种操作,其中查是重点,在写原生sql语句中这也是个难点。下面我们就来看看Realm的CRUD是怎样的

1.添加数据

RealmConfiguration realmConfig = new RealmConfiguration
                .Builder(this)
                .build();
Realm realm = Realm.getInstance(realmConfig);
 public void testAdd() {
        initRealm();
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                for (int i = 0; i < 10; i++) {
                    User user = realm.createObject(User.class);
                    user.setName("user" + i);
                    user.setAge(10 + i);
                    user.setId(UUID.randomUUID().toString());
                }
                showInTextView("10条数据添加成功");
            }
        });
    }

在用Realm进行操作之前需要对Realm作相关的配置操作,Realm中所有的写操作都必须在事务中进行,不然就会报错,记得在Activity的onDestory中调用realm.close()释放资源。上面的代码片段就创建了10个User对象。

2.查询数据

  • 查询全部
 public void testQuery() {
        List<User> users= realm.where(User.class).findAll();
        for (User user: users) {
            showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge());
        }
    }
  • 条件查询,Realm 支持以下查询条件(来源于官网):
    • between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
    • equalTo() 和 notEqualTo()
    • contains()、beginsWith() 和 endsWith()
    • isNull() 和 isNotNull()
    • isEmpty() 和 isNotEmpty()

以下代码片段查询年龄小于15的User

 public void testQueryAgeLessThan15() {
        List<User> users= realm.where(User.class).lessThan("age", 15).findAll();
        for (User user: users) {
            showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge());
        }
    }
  • 聚合查询,支持的聚合操作有sum,min,max,average
    以下代码片段得到所有人的平均年龄
public void testQueryAverageAge() {
        double age = realm.where(User.class).findAll().average("age");
        textView.setText("average age:" + age);
    }

3.更新数据

 public void testUpdate() {
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                User user = realm.where(User.class).equalTo("name", "user9").findFirst();
                if (user != null) {
                    user.setAge(99);
                    user.setName("二逼青年");
                }
                textView.setText("更新成功");
            }
        });
    }

4.删除数据

以下代码片段展示了如何删除指定的对象

 public void testDelete() {
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                User user = realm.where(User.class).equalTo("name", "user0").findFirst();
                if (user != null)
                    user.deleteFromRealm();
                textView.setText("删除成功");
            }
        });
    }

四.进阶用法

通过前面一节的学习,我们基本学会了Realm数据库基本的增删改查操作。
本节来看看Realm还有什么其他用法

1.用json创建对象

在实际开发中我们和json打交道的机会比较多,所以直接从json去创建对象是十分有用的,下面的代码片段展示了怎么去用。

private void testAddFromJson() {
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                String json = "{\n" +
                        "    \"id\": \"uuid1\",\n" +
                        "    \"name\": \"solid\",\n" +
                        "    \"age\": 20\n" +
                        "}";
                String jsons = "[\n" +
                        "    {\n" +
                        "        \"id\": \"uuid1\",\n" +
                        "        \"name\": \"solid\",\n" +
                        "        \"age\": 20\n" +
                        "    },\n" +
                        "    {\n" +
                        "        \"id\": \"uuid2\",\n" +
                        "        \"name\": \"jhack\",\n" +
                        "        \"age\": 21\n" +
                        "    },\n" +
                        "    {\n" +
                        "        \"id\": \"uuid3\",\n" +
                        "        \"name\": \"tom\",\n" +
                        "        \"age\": 22\n" +
                        "    }\n" +
                        "]";
                //realm.createObjectFromJson(User.class, json);
                realm.createAllFromJson(User.class, jsons);
            }
        });
    }

2.数据模型改变的处理

开发中数据模型不可能从一开始创建了,就保证后面的开发过程中不会更改,对于Realm如果其中的某个实体类改变了,而我们没有做任何的处理,就会报错,如果还处于应用的开发的初期,这无所谓,直接清空数据即可,但是如果应用已经发布了,我们就需要去寻找一种解决方案了。

这里的解决方案如下:

public class MyMigration implements RealmMigration {
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        Log.e(MainActivity.TAG, "oldVersion:" + oldVersion + " newVersion:" + newVersion);

        RealmSchema schema = realm.getSchema();

        if (newVersion == 2) {
            schema.get("User")
                    .addField("desc", String.class);
        }
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof MyMigration;
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}
 realmConfig = new RealmConfiguration
                .Builder(this)
                .schemaVersion(2)
                .migration(new MyMigration())
                .build();

3.与RxJava的结合

Realm原生是支持Rxjava的,由于RxJava 是可选依赖,所以在使用的时候需要在app的build文件中添加RxJava库的依赖,下面是使用的代码片段。

public void testRxJava() {
        realm.where(User.class).findAll()
                .asObservable()
                .flatMap(new Func1<RealmResults<User>, Observable<User>>() {
                    @Override
                    public Observable<User> call(RealmResults<User> users) {
                        return Observable.from(users);
                    }
                })
                .subscribe(new Action1<User>() {
                    @Override
                    public void call(User user) {
                        showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge() + " desc:" + user.getDesc());

                    }
                });
    }

这篇文章接到这了,遗憾的是Realm在Windows中没有相关的查看器,只有Mac版的,所以不能直接在Windows中查看Realm数据库中的数据,希望官方后面会有支持吧。更多的资料请查看官方文档。
参考文档:realm-java

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容