Realm基础

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/"; 
    
    @Override
    public 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查询语句与查询的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值