Realm基础

来源:互联网 发布:软件部署实施方案 编辑:程序博客网 时间:2024/06/06 02:13

Realm环境配置

  1. 在工程根目录下的build.gradle添加如下配置:

    buildscript {    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:2.3.1'        classpath "io.realm:realm-gradle-plugin:3.5.0"    }}
  2. 在模块目录下的build.gradle添加如下插件:

    apply plugin: 'realm-android'
  3. 使用Realm之前,先传递context对象完成Realm的初始化,可在Application的onCreate完成初始化操作,如下:

    public class MainApplication extends Application {    @Override    public void onCreate() {        super.onCreate();        Realm.init(this);    }}
  4. Realm的配置分为两种:默认配置和用户自定义配置,先看如下代码:

    private static final String REALM_PATH =Environment.getExternalStorageDirectory().getAbsolutePath() + "/realm_dir/"; @Overridepublic void onCreate() {    super.onCreate();    Realm.init(this);    // 默认配置获取的Realm实例    Realm.getDefaultInstance();    RealmConfiguration.Builder builder = new RealmConfiguration.Builder()        .name("custom.realm")        .directory(new File(REALM_PATH))        .schemaVersion(1)        .modules(Realm.getDefaultModule())        .deleteRealmIfMigrationNeeded()        .encryptionKey(getKey());    // Realm.setDefaultConfiguration(builder.build());    //  用户配置获取的Realm实例    Realm.getInstance(builder.build());}

    从上述代码可知,Realm是以builder来构建RealmConfiguration。RealmConfiguration主要包括数据库名字(name)、数据库地址(directory)、版本号(schemaVersion)、数据库加密密匙(encryptionKey)等,且Realm已内置了一套默认配置的实现,可通过setDefaultConfiguration来修改默认配置。总之,Realm的数据库配置还是相对灵活的,且能满足一般的用户数据。

  5. Realm支持数据库加密,只需配置密匙即可加密数据库。关键在于密匙的管理,一般做法如下:

    1. 先生成RSA密匙对,对于sdk23及以上可使用Android KeyStore,否则自己维护RSA密匙对;
    2. 生成AES密匙;
    3. 用RSA的公匙加密AES密匙;
    4. 存储加密后的AES密匙,如使用SharedPreferences;
    5. 获取被存储的AES密匙,并用RSA私匙解密AES密匙,配置RealmConfiguration即可打开加密数据库。

    总结:使用Android KeyStore减轻了对RSA密匙对的维护工作,只需专注于AES密匙的存储。值得注意的是此处使用RSA的签名验证功能,即用RSA公钥加密AES,RSA私钥解密AES。因为Android KeyStore不对外公开RSA的密匙对,所以不但能加密数据而且还能确保AES密匙的唯一性,意味着解密出来的AES密匙一定能打开已加密的Realm数据库文件。

Realm Models

  1. 因Realm数据库的底层设计,所有的Model必需继承于RealmObject。但Model写法与JavaBean写法无甚差异,比如下实例:

    public class User extends RealmObject {    private String          name;    private int             age;    @Ignore    private int             sessionId;    // Standard getters & setters generated by your IDE…    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 int    getSessionId() { return sessionId; }    public void   setSessionId(int sessionId) { this.sessionId = sessionId; }}
  2. RealmObject支持存储的属性常见类型有:boolean, byte, short, int, long, float, double, String, Date and byte[]。另外还支持RealmObject的子类或者RealmList的集合类型。如下例子:

    public class UserInfo extends RealmObject {    @PrimaryKey    private String userId;    private Job job;    private RealmList<Colleague> colleagues;    public String getUserId() {        return userId;    }    public void setUserId(String userId) {        this.userId = userId;    }    public Job getJob() {        return job;    }    public void setJob(Job job) {        this.job = job;    }    public RealmList<Colleague> getColleagues() {        return colleagues;    }    public void setColleagues(RealmList<Colleague> colleagues) {        this.colleagues = colleagues;    }}public class Job extends RealmObject {    private String jobTitle;    private String companyName;    public String getJobTitle() {        return jobTitle;    }    public void setJobTitle(String jobTitle) {        this.jobTitle = jobTitle;    }    public String getCompanyName() {        return companyName;    }    public void setCompanyName(String companyName) {        this.companyName = companyName;    }}public class Colleague extends RealmObject{    private String name;    private int 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;    }}
  3. 在Model中声明的属性都将被存储,可以通过加Ignore注解来忽略存储。对于static或volatile的属性,会默认忽略,不需加Ignore注解。

  4. RealmObject Model的最大特点是自动更新,是一种内存数据与文件数据的同步策略,可减轻查询数据的消耗。如下例子:

    public void test() {    realm.executeTransaction(new Realm.Transaction() {        @Override        public void execute(Realm realm) {            Dog myDog = realm.createObject(Dog.class);            myDog.setName("Fido");            myDog.setAge(1);        }    });    Dog myDog = realm.where(Dog.class).equalTo("age", 1).findFirst();    realm.executeTransaction(new Realm.Transaction() {        @Override        public void execute(Realm realm) {            Dog myPuppy = realm.where(Dog.class).equalTo("age", 1).findFirst();            myPuppy.setAge(2);        }    });    myDog.getAge(); // => 2}

    5.简单理解,RealmObject Model对应于Realm数据库中的一张表,而一张表有且仅有一个主键。主键属性的类型只能是String或integer类型。

  5. 用法在前面的UserInfo对象中,只需对主键属性添加@PrimaryKey注解即可。
  6. 主键的好处是达到复用RealmObjec的目的,原理是在创建RealmObject对象时借助主键去查询是否存在该对象,存在该对象即可返回,否则创建新对象。
  7. 创建RealmObject对象的三种方式:createObject、copyToRealmOrUpdate与copyToRealm用法如下:

    //第一种:创建新实例//final MyObject obj = Realm.createObject(MyObject.class);final MyObject obj = new MyObject();obj.setId(42);obj.setName("Fish");realm.executeTransaction(new Realm.Transaction() {@Override    public void execute(Realm realm) {        // 第二种:依据主键判断,不存在创建新实例,否则抛异常        // realm.copyToRealm(obj);        // 第三种:依据主键判断,不存在创建新实例,否则更新并返回实例        realm.copyToRealmOrUpdate(obj);    }});
    1. 主键的副作用是有可能带来性能问题,就来创建RealmObject对象来说,使用copyToRealmOrUpdate虽能复用对象,但是其性能瓶颈在于查找与更新实例。

Realm 调试

  1. Stetho是用于调试Realm的便利工具,同时还需要chrome浏览器的支持。
  2. 先在工程根目录的gradle文件添加路径,如下

    allprojects {    repositories {        jcenter()        maven {            url 'https://github.com/uPhyca/stetho-realm/raw/master/maven-repo'        }    }}
  3. 在模块目录的gradle文件添加依赖

    dependencies {    compile 'com.facebook.stetho:stetho:1.5.0'    compile 'com.uphyca:stetho_realm:2.1.0'}
  4. 打开chrome浏览器,输入chrome://inspect,即可开始realm的调试,如下图
    这里写图片描述
    这里写图片描述

  5. 注意在发布正式版本前,需要关闭Stetho,否则容易泄露数据。

Realm Writes

  1. Realm Writes分为插入、更新和删除三种操作,实现的方式是Transaction。
  2. Transaction提交与取消,模板如下

        // Obtain a Realm instance    Realm realm = Realm.getDefaultInstance();    realm.beginTransaction();    //... add or update objects here ...    realm.commitTransaction();
        realm.beginTransaction();    Dog dog = realm.createObject(Dog.class);    //  ...    realm.cancelTransaction();
  3. 一个完整事务是以beginTransaction开始,以提交或取消二选一的方式来结束一个事务。

  4. Realm事务的执行是同步进行,因此在UI线程执行事务有可能造成ANR,解决方法是使用Realm.executeTransactionAsync异步执行,如下代码

    public void executeTransactionAsync() {    realm.executeTransactionAsync(new Realm.Transaction() {        @Override        public void execute(Realm bgRealm) {            Dog myDog = realm.createObject(Dog.class);            myDog.setName("Mike");            myDog.setAge(4);        }    }, new Realm.Transaction.OnSuccess() {        @Override        public void onSuccess() {            // Transaction was a success.        }    }, new Realm.Transaction.OnError() {        @Override        public void onError(Throwable error) {            // Transaction failed and was automatically canceled.        }    });}
  5. Realm推荐使用executeTransaction方法来执行事务,其实就是对前面模板代码的封装,如下代码:

    public void executeTransaction() {    realm.executeTransaction(new Realm.Transaction() {        @Override        public void execute(Realm realm) {            Dog myDog = realm.createObject(Dog.class);            myDog.setName("Jack");            myDog.setAge(12);        }    });}

Realm Queries

  1. Realm使用RealmQuery来封装SQL语句,体现如下:

    public void query() {    // Build the query looking at all users:    RealmQuery<User> query = realm.where(User.class);    // Add query conditions:    query.equalTo("name", "John");    query.or().equalTo("name", "Peter");    // Execute the query:    RealmResults<User> result1 = query.findAll();}

    上述代码可简写如下:

    public void query() {    RealmResults<User> result2 = realm.where(User.class)    .equalTo("name", "John")    .or()    .equalTo("name", "Peter")    .findAll();}

    不难发现,where用于指定数据库表名,equalTo等则是匹配条件,find则是执行查询操作。

  2. 查询的结果封装在RealmResults,这是Realm实现的一个集合。

  3. 删除查询结果,如下实例:

    public void delete() {    // obtain the results of a query    final RealmResults<Dog> results = realm.where(Dog.class).findAll();    // All changes to data must happen in a transaction    realm.executeTransaction(new Realm.Transaction() {        @Override        public void execute(Realm realm) {            // remove single match            results.deleteFirstFromRealm();            results.deleteLastFromRealm();            // remove a single object            Dog dog = results.get(5);            dog.deleteFromRealm();            // Delete all matches            results.deleteAllFromRealm();        }    });}

Realm 总结

Realm的核心主要包括环境配置、models、write、query几大块:通过RealmConfiguration实现个性化配置;继承RealmObject完成数据持久化;借助Transaction完成数据的插入、更新和删除操作;使用RealmQuery和RealmResults分别封装SQL查询语句与查询的结果。

原创粉丝点击