Android十八章:Realm-in-android

Realm介绍

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

快速入门

只需两步

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

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'

apply plugin: 'com.android.application'
apply plugin: 'realm-android'

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

Realm的模型

自定义类要继承RealmObject,注意如果重载了带参数构造方法,这里必须要多写一个无参数的构造方法不然会抛出javac的异常。不要我问我为什么。

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<E>,比如

public class Person extends RealmObject {
    @PrimaryKey
    private long id;
    private String name;
    private RealmList<Dog> mDogRealmList;
    }

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

@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实例

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();,确保数据的一致性。

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会深拷贝一个变量到数据库包括主键,如果主键重复就会抛出异常,拷贝之后主键不能修改。

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

//同步新增数据
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        Dog dog = realm.copyToRealm(new Dog(1, "2", 3));
        dog.setName("pp");
    }
});
//异步修改 查询
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<E>对象支持以下查询条件。

  1. between(),greaterThan(), lessThan(), greaterThanOrEqualTo() 和lessThanOrEqualTo();
  2. equalTo()和notEqualTo()
  3. contains(),beginsWith()和endsWith()
  4. isNull()和isNotNull()
  5. isEmpty()和isNotEmpty()
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修改

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

  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<E>的changeListener

监听RealmResult内容变化。

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集合

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字符串

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<E> 使用

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合并信息的检查。

     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();

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是上一个版本号,要做什么需求。

//你还可以做以下操作
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

    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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SeanCheney的专栏

《利用Python进行数据分析·第2版》第6章 数据加载、存储与文件格式6.1 读写文本格式的数据6.2 二进制数据格式6.3 Web APIs交互6.4 数据库交互6.5 总结

访问数据是使用本书所介绍的这些工具的第一步。我会着重介绍pandas的数据输入与输出,虽然别的库中也有不少以此为目的的工具。 输入输出通常可以划分为几个大类:读...

60860
来自专栏博岩Java大讲堂

Java集合--阻塞队列(ArrayBlockingQueue)

27330
来自专栏数据小魔方

左手用R右手Python系列之——noSQL基础与mongodb入门

12月的第一天,祝所有小伙伴儿的12月都能够被温柔以待。 能在学校悠哉写推送的日子所剩不多了,为了珍惜剩下所剩不多的推送机会,打算12月写一些实践性强一些的内...

57870
来自专栏butterfly100

ConcurrentHashMap源码阅读

1. 前言 HashMap是非线程安全的,在多线程访问时没有同步机制,并发场景下put操作可能导致同一数组下的链表形成闭环,get时候出现死循环,导致CPU利用...

32170
来自专栏大内老A

依赖注入[5]: 创建一个简易版的DI框架[下篇]

为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架。在《依赖注入[4]: 创建...

9130
来自专栏chenssy

【死磕Java并发】—–J.U.C之阻塞队列:ArrayBlockingQueue

ArrayBlockingQueue,一个由数组实现的有界阻塞队列。该队列采用FIFO的原则对元素进行排序添加的。 ArrayBlockingQueue为有界且...

40360
来自专栏码匠的流水账

聊聊lombok构造模式的参数校验

那么问题来了,如果在build方法调用,返回对象之前进行参数校验呢。理想的情况当然是lombok提供一个类似jpa的@PrePersist的钩子注解呢,可惜没有...

9620
来自专栏Spark生态圈

[spark] Shuffle Read解析 (Sort Based Shuffle)

本文将讲解shuffle Reduce部分,shuffle的下游Stage的第一个rdd是ShuffleRDD,通过其compute方法来获取上游Stage S...

13910
来自专栏数据小魔方

Julia语言初体验

最近MIT发布的julia 1.0.0版,据传整合了C、Python、R等诸多语言特色,是数据科学领域又一把顶级利器。

2.9K20
来自专栏JavaEdge

CurrentHashMap原理从7到81 为什么要使用ConcurrentHashMap2 ConcurrentHashMap的结构3 ConcurrentHashMap的初始化5 Concurre

2.4K90

扫码关注云+社区

领取腾讯云代金券