Realm应用背景

Android自带的SQLite数据库,在多数场合能够满足我们的需求,但随着app广泛使用,SQLite也暴露了几个不足之处:
1、开发者编码比较麻烦,而且还要求开发者具备SQL语法知识;
2、SQLite默认没有加密功能,手机一旦丢失容易导致数据库被破解;
3、SQLite底层采用java代码,导致性能提升存在瓶颈;


基于以上几点,Android上的各种ORM应运而生(ORM全称Object Relational Mapping,即对象关系映射),最常见的便是greenDAO了。greenDAO是一个将对象映射到SQLite数据库中的ORM解决方案,它在github上的地址是https://github.com/greenrobot/greenDAO,下面是greenDAO相比直接使用SQLite的几个改进点:
1、简化数据库操作的编码,开发者可以不用熟悉SQL语法;
2、使用灵活,可在实体类中自定义类和枚举类型;
3、号称是基于SQLite的ORM框架中性能最好的;(博主没对比greenDAO与直接使用SQLite的性能差异,所以只能是跟其他ORM框架比较,比如ORMLite、sugarORM等等)
但是greenDAO使用的数据库引擎还是SQLite,因此某些方面并没有本质的改善,比如数据库的加密、数据库操作的性能等等。


对于Realm来说,这些改善就是可能的了,因为Realm有自己的数据库引擎,而且引擎使用C++编写,性能比java引擎的SQLite有数倍提升。Realm使用C++引擎还有一个好处,就是可以跨平台使用,不但能用于Android,也能用于IOS。Realm的第三个好处是,它具有很多移动设备专用数据库的特性,比如支持JSON、流式api、数据变更通知,以及加密支持,这些都为开发者带来了方便。


Realm环境搭建

Realm支持Eclipse的最后版本是0.87.5,更新的版本只支持AndroidStudio,不再支持Eclipse了,所以这里就以0.87.5为例进行说明。


0.87.5的Realm下载页面是https://realm.io/docs/java/0.87.5/#eclipse,github上最新版本的地址是https://github.com/realm/realm-java。把Realm加入到工程,除了引用realm-android-0.87.5.jar,还得加入armeabi目录下的so文件librealm-jni.so。现在编译通过了,可是运行时又坑爹了,居然报错“java.lang.IllegalArgumentException: Country is not part of the schema for this Realm”,原因是Realm采用了注解Annotation方式,所以得先让我们的Eclipse支持注解才行。类似的情况,也存在于ButterKnife这个注入框架。


按照Realm官网的说明步骤,竟然发现我们最新的ADT,在“Properties”——“Java Compiler”下并没有“Annotation Processing”。网上转悠了一圈,找到了如下解决步骤:
1、依次选择“Help”——“Install New Software”
2、下拉选择Juno,即“Juno - http://download.eclipse.org/releases/juno”
3、在Name列表中点开“Programming Languages”,然后勾选“Eclipse Java Development Tools”(最新版本是3.8.2)
4、点击“Next”按钮,执行安装操作
5、安装完毕重启ADT,就可以在“Java Compiler”下找到“Annotation Processing”了


装好Annotation插件,只是万里长征的第一步,接下来我们还得配置Eclipse,使之支持Annotation,具体步骤如下:
1、右击我们的工程,依次选择“Properties”——“Java Compiler”——“Annotation Processing”,勾选“Enable project specific settings”,并点击“Apply”按钮,然后工程会重新编译;
2、继续打开“Annotation Processing”——“Factory Path”,勾选“Enable project specific settings”,然后点击“Click Add JARs”按钮,选择工程libs目录下的realm-android-0.87.5.jar,点击“OK”按钮,然后工程又会重新编译;
3、为了确保注解的处理器一直工作,我们得在所有RealmObject派生类的前一行加上注解:@RealmClass


另外,正式的app都会进行代码混淆处理,为了避免混淆操作影响Realm的使用,我们要在proguard-project.txt增加如下配置:
-keep class io.realm.annotations.RealmModule-keep @io.realm.annotations.RealmModule class *-keep class io.realm.internal.Keep-keep @io.realm.internal.Keep class * { *; }-dontwarn javax.**-dontwarn io.realm.**


Realm编码开发

数据库配置RealmConfiguration

RealmConfiguration是Realm的配置工具类,它采用了建造者模式来构建,下面是RealmConfiguration类的常用方法:
Builder(context) : 初始化RealmConfiguration的建造器。
Builder.name : 指定数据库的名称。如不指定默认名为default。
Builder.encryptionKey : 指定数据库的密钥。密钥可由SecureRandom的nextBytes方法获得,如不指定密钥则默认不加密。一旦建立加密的数据库,如果访问时密钥不正确,则Realm会扔出异常“java.lang.IllegalArgumentException: Illegal Argument: Invalid format of Realm file”。
Builder.schemaVersion : 指定数据库的版本号。如果不指定默认版本号为0,若原版本号与现版本号不一致,Realm会抛出异常“io.realm.exceptions.RealmMigrationNeededException: RealmMigration must be provided”。
Builder.migration : 指定迁移操作的迁移类,当Realm发现新旧版本号不一致时,会自动使用该迁移类完成迁移操作。
Builder.deleteRealmIfMigrationNeeded : 声明版本冲突时自动删除原数据库。
Builder.inMemory : 声明数据库只在内存中持久化。这意味着插入数据库后不能立即关闭数据库,因为一旦关闭数据库则内存中的数据马上丢失。若数据采用在文件中持久化,则无需担心关闭数据库导致数据丢失的问题。

build : 完成配置构建。
getRealmFolder : 获取数据库的持有者,返回File对象。
getRealmFileName : 获取数据库的文件名字符串。
getEncryptionKey : 获取数据库的加密密钥。
getSchemaVersion : 获取数据库的版本号。
getMigration : 获取迁移操作的迁移类。
shouldDeleteRealmIfMigrationNeeded : 判断是否声明版本冲突时自动删除原数据库。
getDurability : 返回数据持久化的方式


数据表对象RealmObject

RealmObject是数据表的实体基类,所有Realm的实体类都要从RealmObject派生而来。Realm实体类除了字段声明与set方法、get方法之外,还要加上若干必要的注解,举例如下:
@RealmClass : 加在类名前面,表示这是一个Realm实体类。
@PrimaryKey : 加在字段前面,表示该字段是主键。
@Required : 加在字段前面,表示该字段非空。
@Ignore: 加在字段前面,表示该字段不是Realm表的字段。因为有时我们需要处理一些额外的信息,但又不需要把这些信息保存到数据库。


下面是声明一个实体类的代码例子:
import io.realm.RealmObject;import io.realm.annotations.Ignore;import io.realm.annotations.PrimaryKey;import io.realm.annotations.RealmClass;import io.realm.annotations.Required;@RealmClasspublic class Country extends RealmObject {@PrimaryKeyprivate String code;@Requiredprivate String name;@Requiredprivate int population;@Ignoreprivate String remark;public Country() {}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPopulation() {return population;}public void setPopulation(int population) {this.population = population;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}}


数据库管理Realm

Realm是数据库管理工具类,可完成DDL和DML操作,下面是Realm类的常用方法:
getInstance : 获得一个数据库实例。可传入RealmConfiguration对象,若没有传入RealmConfiguration,则默认操作名为default.realm的数据库文件。
setDefaultConfiguration : 设置默认的RealmConfiguration配置。
deleteRealm : 删除指定配置的数据库。
isClosed : 判断数据库是否关闭。
close : 关闭数据库。
beginTransaction : 开始事务,需与commitTransaction配合使用。
commitTransaction : 结束事务,需与beginTransaction配合使用。
createObject : 从RealmObject类创建一条数据库记录,后面直接使用该类的设置方法即可写入字段值。
copyToRealm : 把指定RealmObject类插入数据库,如已存在主键相同的记录则扔出异常。
copyToRealmOrUpdate : 把指定RealmObject类插入数据库,如已存在主键相同的记录则更新原记录。
remove : 删除指定数据库记录。
executeTransaction : 单独对指定Realm执行事务,用于需要对事务失败进行处理的场合。
where : 查询指定表。返回RealmQuery对象。
distinct : 查询指定表指定记录的去重队列。返回RealmResults队列。


下面是Realm插入记录的代码示例:
mRealm = Realm.getInstance(mConfig);mRealm.beginTransaction();Country country1 = mRealm.createObject(Country.class);country1.setName("北京");country1.setPopulation(5165800);country1.setCode("beijing");Country country2 = new Country();country2.setName("上海");country2.setPopulation(5999800);country2.setCode("shanghai");mRealm.copyToRealm(country2);Country country3 = new Country();country3.setName("福州");country3.setPopulation(876580);country3.setCode("fuzhou");mRealm.copyToRealmOrUpdate(country3);mRealm.commitTransaction();mRealm.close();


数据库查询RealmQuery

RealmQuery是数据库查询工具类,其对象由Realm的where方法获得,下面是RealmQuery类的常用方法:

查询条件
isNull : 指定字段为空。
isNotNull : 指定字段非空。
equalTo : 指定字段等于多少。
notEqualTo : 指定字段不等于多少。
greaterThan : 指定字段大于多少。
greaterThanOrEqualTo : 指定字段大等于多少。
lessThan : 指定字段小于多少。
lessThanOrEqualTo : 指定字段小等于多少。
between : 指定字段位于什么区间。
contains : 指定字段包含什么字符串。
beginsWith : 指定字段以什么字符串开头。
endsWith : 指定字段以什么字符串结尾。

返回结果集的运算结果
sum : 对指定字段求和。
average : 对指定字段求平均值。
min : 对指定字段求最小值。
max : 对指定字段求最大值。
count : 求结果集的记录数量。
findAll : 返回结果集所有字段,返回值为RealmResults队列
findAllSorted : 排序返回结果集所有字段,返回值为RealmResults队列


下面是Realm查询操作的代码示例:
mRealm = Realm.getInstance(mConfig);RealmResults<Country> results = mRealm.where(Country.class).greaterThan("population", 1000000).findAll();String desc = String.format("找到%d条记录", results.size());for (int i = 0; i < results.size(); i++) {Country result = results.get(i);desc = String.format("%s\n其中城市%s的代码是%s,人口有%d", desc,result.getName(), result.getCode(),result.getPopulation());}tv_hello.setText(desc);if (mRealm.isClosed() != true) {mRealm.close();}


数据库迁移RealmMigration

app升级时可能伴随着数据库升级,对于Realm来说,数据库升级就是迁移操作,把原来的数据库迁移到新结构的数据库。编码中应对数据库迁移有三种方式:
1、构建RealmConfiguration时指定数据库版本号,如果原版本号与现版本号不一致,Realm会抛出异常RealmMigrationNeededException。代码中捕获异常RealmMigrationNeededException后,调用migrateRealm方法执行迁移操作,示例代码如下:
RealmConfiguration config0 = new RealmConfiguration.Builder(this).name("default0").schemaVersion(3).build();try {realm = Realm.getInstance(config0);} catch (RealmMigrationNeededException e) {e.printStackTrace();// You can then manually call Realm.migrateRealm().Realm.migrateRealm(config0, new CustomMigration());realm = Realm.getInstance(config0);}

2、构建RealmConfiguration时指定数据库版本号,同时也指定迁移类,这样如果原版本号与现版本号不一致,Realm会自动使用迁移类执行迁移操作。示例代码如下:
RealmConfiguration config1 = new RealmConfiguration.Builder(this).name("default1").schemaVersion(3).migration(new CustomMigration()).build();realm = Realm.getInstance(config1); // Automatically run migration if needed

3、构建RealmConfiguration时指定数据库版本号,同时声明版本冲突时自动删除原数据库,不过该方法一般不用,因为该方法会暴力删除所有数据。示例代码如下:
RealmConfiguration config2 = new RealmConfiguration.Builder(this).name("default2").schemaVersion(3).deleteRealmIfMigrationNeeded().build();realm = Realm.getInstance(config2); // WARNING: This will delete all data in the Realm though.





点此查看Android开发笔记的完整目录

更多相关文章

  1. Android——SQLite数据库使用详解
  2. Android数据存储之SQLite
  3. 开发者眼中的Android手机平台
  4. Android程序猿来搭建服务器
  5. Android(安卓)通过反射随手可得的Application对象
  6. android开发系列之数据存储
  7. 在android中使用SQLite数据库
  8. Kotlin学习笔记:为什么要学习kotlin和kotlin的集成
  9. 记录:Android(安卓)SQLite的使用

随机推荐

  1. mysql server 8.0.3安装配置方法图文教程
  2. mysql 8.0.12 winx64下载安装教程
  3. RHEL7.5下mysql 8.0.11安装教程
  4. Linux下mysql 8.0安装教程
  5. CentOS 6、7下mysql 5.7 详细安装教程
  6. linux下mysql忘记密码的解决方法
  7. CentOS 7下mysql 5.7 安装教程
  8. MySQL错误代码1862 your password has ex
  9. CentOS 7安装MySQL的详细步骤
  10. MySQL 5.7.22 二进制包安装及免安装版Win