Realm-in-android-1

Realm介绍

Realm是一个开源的ORM概念的(对象关系映射)移动数据库,可以在Android ,ios ,java各个平台上使用,性能秒杀sqlite等数据库比如(greendao)。

快速入门

只需两步

在项目的build.gradle中dependencies输入classpath “io.realm:realm-gradle-plugin:2.3.1”,这里要双引号。这里要双引号。这里要双引号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
repositories {

jcenter()

}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath "io.realm:realm-gradle-plugin:2.3.1"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

在app的bulid.gradle输入apply plugin: ‘realm-android’

1
apply plugin: 'realm-android'

★以上操作完成了realm在as的配置了。

Realm的模型

自定义类要继承RealmObject,注意这里必须要有一个无参数的构造方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Dog extends RealmObject {
private String name;
private int age;

public Dog() {

}

public Dog(String name, int age) {
this.name = name;
this.age = age;
}

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;
}
}

如果类A中包含着其他类的集合这时候要用到ResultList,比如

1
2
3
4
5
6
public class Person extends RealmObject {
@PrimaryKey
private long id;
private String name;
private RealmList<Dog> mDogRealmList;
}

如果你的自定义类已经继承了其他父类,你也可以实现RealmModel来建造realm对象模型。

1
2
3
4
5
6
7
@RealmClass
public class User implements RealmModel {

private String name;
private int id;
//...
}

Realm注解说明

@RealmClass 当实现RealmModel接口的类要加上这个注解。

@Required 修饰不能为空的成员变量

@Ignore 修饰不写入数据库的变量

@PrimaryKey 设置该成员变量为类的主键

@Index 加快查询速度,不过会让插入数据时变慢

Realm初始化

在自定义Applciation中Realm.init(this);

获取Realm实例

1
realm = Realm.getDefaultInstance();

这是获取默认配置的Realm,默认保存在data/data/packageName/files/default.realm 你也可以自定义RealmConfiguration,通常是自定义文件名,加密的key,数据库版本号和是否删除合并前的数据等。Realm实现了closeable接口,所以每次的getInstance,到最后关闭使用后都要调用close方法。比如在activity的ondestroy调用realm.close();

Realm写入

Realm是一个MVCC架构,同一线程的读写操作不影响获取数据,但是多线程读取写入操作就要用到事务来确保获取数据一致性和线程安全。的是放在事务transcation里面执行,确保整个事务的操作都被提交或者全部取消操作调用realm.cancelTranscation();,确保数据的一致性。

1
2
3
4
5
6
realm = Realm.getDefaultInstance();
realm.beginTransaction();
Dog d=new Dog("a",1);
Dog b=realm.copyToRealm(d);//这里的copyToRealm相当于深拷贝了一个d变量。对原来的d变量没任何影响。
b.setName("b");
realm.commitTransaction(); //最后往数据库写入一个dog变量b

♥copyToRealm会深拷贝一个变量到数据库包括主键,如果主键重复就会抛出异常,拷贝之后主键不能修改。

当两个线程同时进行写入操作,另外一个会造成主线程阻塞,所以要调用异步事务避免主线程阻塞。

1
2
3
4
5
6
7
8
//同步新增数据
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Dog dog = realm.copyToRealm(new Dog(1, "2", 3));
dog.setName("pp");
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//异步修改 查询
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Dog dog = realm.copyToRealm(dogOne);
dog.setName("apple");

}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
RealmResults<Dog> list = realm.where(Dog.class).findAll();
for (int i = 0; i < list.size(); i++) {
Log.i(TAG, "onSuccess: " + list.toString());
}
}
});

realm的主键,在oncreate方法加入设置主键的RealmObject方法,下次调用oncreate没有判断主键是否exist就加入数据库就会报错。而在oncreate方法没加入没设置主键的realmobject类 ,下次调用oncreate方法就会在自启动数据库文件追加。

Realm 查询

查询都是返回一个RealmResults对象支持以下查询条件。

  1. between(),greaterThan(), lessThan(), greaterThanOrEqualTo() 和lessThanOrEqualTo();
  2. equalTo()和notEqualTo()
  3. contains(),beginsWith()和endsWith()
  4. isNull()和isNotNull()
  5. isEmpty()和isNotEmpty()
1
2
3
4
RealmResults<Dog> list=realm.where(Dog.class).lessThan("age",1).findAll();
for (int i = 0; i < list.size(); i++) {
Log.i(TAG, "execute: "+list.get(i).getName());
}

Realm修改

修改操作要在一个事务里面完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dog = new Dog(1, "a", 1);
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
dog = realm.copyToRealm(dog);
dog.setAge(2);
dog.setName("kiki");


RealmResults<Dog> list = realm.where(Dog.class).equalTo("id", 1).findAll();
list.get(0).setName("ab");



}
});

RealmResult的changeListener

监听RealmResult内容变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
RealmResults<Dog> list = realm.where(Dog.class).lessThan("id", 3).findAll();


realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {

Dog dog = realm.createObject(Dog.class);
dog.setId(2);
dog.setName("aaaa");
dog.setAge(3);


}
});
list.addChangeListener(new RealmChangeListener<RealmResults<Dog>>() {
@Override
public void onChange(RealmResults<Dog> element) {
Log.i(TAG, "onChange: " + element.toString());
}
});

//最后需要在activity或者fragment的生命周期比如ondestory调用
list.removeChangeListeners();//删除全部的listener
list。removeChangeListener(callback);//删除一个callback

Realm的删除

继续上面的例子查询id小于3的realmresult集合

1
2
3
4
5
6
7
8
9
10
list.addChangeListener(new RealmChangeListener<RealmResults<Dog>>() {
@Override
public void onChange(RealmResults<Dog> element) {
element.deleteFirstFromRealm();//删除第一条数据
element.deleteAllFromRealm();//删除全部数据
element.deleteFromRealm(0);//删除指定数据
element.deleteLastFromRealm();//删除最后一条数据
element.get(1).deleteFromRealm();//删除指定obejct
}
});

Realm添加一个json字符串

1
2
3
4
5
6
7
8
9
10
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.createObjectFromJson(Dog.class,"{\n" +
" \"id\": 1,\n" +
" \"name\": \"bili\",\n" +
" \"age\": 12\n" +
"}");
}
});

copyFromRealm,copyToRealm和createObject区别

  • copyFromRealm传入一个RealmObject 拷贝realm数据库中的一个变量并拷贝他的所有属性。
  • copyToRealm 传入一个Obeject 拷贝这个Object的所有属性到realm数据库中
  • createObject 传入一个class 并且赋值他的成员变量为默认值null 或者需要后期赋值使用

RealmResult 使用

1
2
3
4
5
RealmResults<Dog> list = realm.where(Dog.class).findAll();
list.sum("age");
list.max("age");
list.min("age");
list.average("age");

比如获取dog类的所有对象,求age的总和,最大值,最小值,平均值

DynamicRealm

DynamicRealm是Realm的变种类,可以操作没继承RealmObject的类,操作类,当然是以字符串的形式操作,而不是RealmObject,他的默认配置少了schema版本号,migration合并信息的检查。

1
2
3
4
5
6
7
8
9
DynamicRealm dynamicRealm = DynamicRealm.getInstance(new RealmConfiguration.Builder().build());
dynamicRealm.executeTransaction(new DynamicRealm.Transaction() {
@Override
public void execute(DynamicRealm realm) {
DynamicRealmObject person = realm.createObject("Person",1);
person.setString("name", "kik");

}
});

Realm的close

Realm实现了closeable接口,所以每次的getInstance,到最后关闭使用后都要调用close方法。比如在activity的ondestroy调用realm.close();

比如在子线程getIntstance一次,需要在子线程结束前调用一次close();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyRunnable implements Runnable{

@Override
public void run() {
try {
Realm realm=Realm.getDefaultInstance();

} catch (Exception e) {
e.printStackTrace();
} finally {
realm.close();

}
}
}

Realm 版本迁移

如果realm版本是1,现在要升级realm版本是2并且数据解构改变了比如新增了一个RealmObejct的成员变量,如果default.realm存在旧数据,会升级失败。需要要设置migration合并规则。

要自定义一个RealmConfiguration变量 ,重写migrate方法判断oldVersion是上一个版本号,要做什么需求。

1
2
3
4
5
6
7
8
9
10
//你还可以做以下操作
addField("key",long.class);//加一个成员变量key
removeField("key");//去掉一个成员变量key
addRealmListField("dogs",schema.get("Dog"));//加上Realmlist变量dogs
addRealmObjectField("dog",schema.get("Dog"));//加上realmobject变量dog
transform(new RealmObjectSchema.Function(){
public void apply(DynamicRealmObject obj){
obj.set("fullname",obj.getString("firstName")+" "+obj.getString("lastName"))
}
});//把firstname lastname赋值给fullname

比如版本升级加上key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

RealmMigration mRealmMigration=new RealmMigration() {
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema=realm.getSchema();
/*
//version 0
class Dog

private long id;
private String name;
private int age;

//version 1
class Dog
private long key;
private long id;
private String name;
private int age;

*/




//version 0 to version 1
if(oldVersion==1){
schema.get("Dog")
.addField("key",long.class);
/* .addRealmObjectField("dogs",schema.get("Dog"))
.addRealmObjectField("dog",schema.get("Dog"));*/

oldVersion++;
}
}
};


//最后
realm = Realm.getInstance(PPApplicaion.mMigrationConfiguration);

总结

  1. Realm很多种情况修改数据要配合事务使用。
  2. Realm以一个RealmObject作为一个表的功能。
  3. realm的getInstance和close要结对使用
  4. 需要注意RealmResult移除listener