Realm Java 使用

需求

由于项目的定位是工具,所以需要采用纯离线方式实现,这对客户端的开发者来说,无疑是一个大麻烦,因为还要涉及到数据的保存和同步,没办法,项目需要,只能开干

Android ORM 框架对比

项目规划的时间较短,没时间去自己实现一个数据库,好在现在已经有很多开源的ORM框架,下面这个网站是介绍目前比较流行的开源的ORM框架,地址是https://android.libhunt.com/categories/1414-orm,这里,我选择了 Realm Java

Realm Java

先放一张它官网对他的介绍截图

逼格不要太高。

realm是一个跨平台移动数据库引擎,支持Android、OC、React Native、Swift等语言。是第一个专门针对移动平台设计的数据库。目标是取代SQLite。

性能

这也是我选择它的原因之一,在性能方面表现非常抢眼,下面是它官网放出的一个性能对比
https://realm.io/news/realm-for-android/#realm-for-android

基本操作

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Create a RealmConfiguration that saves the Realm file in the app's "files" directory
RealmConfiguration realmConfig = new RealmConfiguration.Builder(getApplicationContext())
.name("moon.realm")
.deleteRealmIfMigrationNeeded()//调试时用
.build();
Realm.setDefaultConfiguration(realmConfig);
//获取
Realm mRealm= Realm.getDefaultInstance();
//为了方便全局获取,我将Realm的获取放在了BaseActivity中
public Realm getRealm() {
return mRealm;
}

这里有个原则必须要注意:realmConfig的build的线程和Realm获取的线程必须要保持一致否则就会抛出如下异常

1
Caused by: java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.

事务

所有的写操作(添加、修改和删除对象),必须包含在写入事务(transaction)中。写入事务可以提交或取消
事务的创建有两种方式

1
2
3
4
5
6
7
8
9
10
11
12
//方式一
getRealm().beginTransaction();
//... add or update objects here ...
getRealm().commitTransaction();
//方式二
getRealm().executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//...add or update objects here ...
}
});

后面在写为了方面查看,我就不加入添加事务代码了,但是大家在使用中一定要加上,否则运行会报错的

首先我们定义个model

1
2
3
4
5
6
7
8
public class Profile extends RealmObject {
@PrimaryKey
public String id = UUID.randomUUID().toString();;
public String username;
public String avatar_url;
public int duration;
public int cycle;
}

这里只要我们继承了RealmObject,数据库在初始化的时候就会创建一个表名为Profile的表,字段为id、username、avatar_url、duration、cycle,其中带有注解@PrimaryKey的字段为主键

由于Realm不支持ID自动递增,所以采用的UUID的方式(有点挫)

增加数据一般有两个方法

1
2
3
4
5
6
7
8
9
10
//方式一
Profile profile = new Profile();
profile.username = "loody";
//...
getRealm().copyToRealm(profile)
//方式二
Profile profile = getRealm().createObject(Profile.class)
profile.username = "loody";
//...

1
2
Profile profile = getRealm().copyToRealm(profile);
profile.deleteFromRealm();

1
2
Profile profile = getRealm().copyToRealmOrUpdate(profile);
profile.username = "jay"

这里有一点要注意,调用copyToRealmOrUpdate()方法的前提是Profile必须要定义主键

1
2
3
4
5
6
7
8
//集合
RealmResults<Profile> mAllProfiles = getRealm().where(Profile.class).findAll();
//集合中的第一个
Profile profile = mAllPeriods.first();
//集合中的最后一个
Profile profile = mAllPeriods.last();

查询条件

Realm 支持以下查询条件:

between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
equalTo() 和 notEqualTo()
contains()、beginsWith() 和 endsWith()
isNull() 和 isNotNull()
isEmpty() 和 isNotEmpty()

1
2
///查询 duration 在5~7(包括)天的人
RealmResults<Profile> mProfiles = getRealm().where(Profile.class).greaterThanOrEqualTo("duration",5).lessThanOrEqualTo("duration",7).findAll();

数据库迁移

当数据库结构发生改变的时候,我们需要配置Migration来实现数据迁移的操作。 比如要新增属性,新增表等

首先我们在初始化数据库的时候要设定当前版本的版本号schemaVersion

1
2
3
4
5
RealmConfiguration realmConfig = new RealmConfiguration.Builder(getApplicationContext())
.name("moon.realm")
.schemaVersion(1//每次数据库发生变化需要改变此值,默认为0
.migration(new MyMigration())//迁移的配置
.build();

接着在不同的版本下做相应的配置

1
2
3
4
5
6
7
8
9
10
11
12
public class MyMigration implements RealmMigration {
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema = realm.getSchema();
if (oldVersion == 1) {
schema.create("Note").addField("name", String.class);//创建Note表并添加name字段,String
schema.get("Profile").addField("age", int.class);//向Profile表新增age字段,数据类型为int
oldVersion++;
}
}
}

数据库查看

数据库创建好后,我们怎样方便实时查看我们的数据文件呢?因为realm不是基于sqlite实现的,这里我们要借助facebook调试工具–>Stetho

引用方式很简单,在build.gradle加入

1
2
3
4
5
6
repositories {
maven { url 'https://github.com/uPhyca/stetho-realm/raw/master/maven-repo' }
}
compile 'com.facebook.stetho:stetho:1.3.1'
compile 'com.uphyca:stetho_realm:0.9.0'//专门针对realm的插件

初始化

1
2
3
4
5
Stetho.initialize(
Stetho.newInitializerBuilder(this)
.enableDumpapp(Stetho.defaultDumperPluginsProvider(this))
.enableWebKitInspector(RealmInspectorModulesProvider.builder(this).build())
.build());

最后我们在浏览器中输入chrome://inspect即可查看了

以上是对Realm Java的一些基本用法的讲解,后面有机会会讲一些它的复杂用法