开场白

  记得我第一次发现Realm的时候是因为手动SQL的繁琐,让我在网上搜索着各种第三方开源的封装的库,搜到了比如GreenDao之类的,然后在知乎上看到了Realm,然后上Realm官网看了介绍,惊叹她的神奇,居然完全用对象的方式来操作数据库,并且速度据官方介绍读取是Sqlite的2倍多,惊叹之余,立马写了个Demo测试下

  • 插入一张官方图
    查询速度
  • Poker扑克计分器 已经传到github上了,这是我第一次使用Realm,当时还是2.1版本,现在已经3.0(在我写完这篇博客时,再去官网看了眼已经3.1了...- -!!)

  使用如此方便,速度如此之快,并且支持全移动端的数据库,还是开源项目(也有收费版本),优点简直数不过来

  所以让我常常在场景合适时,在正式项目中使用它

添加依赖

Step 1:

// The project level - build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // Realm 3.0
        classpath "io.realm:realm-gradle-plugin:3.0.0"
    }
}

Step 2:

// The application level - build.gradle(在最上面的位置)
apply plugin: 'realm-android'

初始化

// Realm 初始化
// Call `Realm.init(Context)` before creating a RealmConfiguration
Realm.init(mContext);
// 用指定的名称作为数据库名
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name(mRealmName).build();
Realm.setDefaultConfiguration(realmConfiguration);

使用

对象的使用

  • extends RealmObject直接使用

可以直接用对象操作,当然也可以用静态方法操作,对象操作例如:realmBean.deleteFromRealm();

  • implements RealmModel需要在类上注解@RealmClass

只能用静态方法操作,例如:RealmObject.deleteFromRealm(realmBean);

// 初始化
Realm.init(this);
// 只作为普通对象,不增加数据库内容,不是持久层
final RealmFriendBean bean = new RealmFriendBean();

try (Realm realm = Realm.getDefaultInstance()) {
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            // 复制对象到数据库,并返回持久层对象,相同主键已存在会报错,表示不是更新数据库,是完全的新增
            realm.copyToRealm(bean);
            
            // 直接创建托管对象,第二个参数为主键,没有可以不填,有的话必须填,不可以在创建完毕后填,因为创建对象即写入数据库,所以也不可以创建重复主键的对象
            // Realm没有主键自增功能,需要手动自增,下面有介绍我的一种方法
            // 而且必须有空构造,所以这种创建方法使用场景比较狭隘
            RealmFriendBean friendBean = realm.createObject(RealmFriendBean.class, 123);
            
            // 如果存在就修改,即使是null也会修改已存在的值,所以只是修改个别字段不能直接JSON反射成对象修改
            RealmFriendBean toRealmOrUpdate = realm.copyToRealmOrUpdate(bean);
            
            // 从数据库拷贝出副本,只修改内存对象,不修改持久层
            RealmFriendBean fromRealm = realm.copyFromRealm(toRealmOrUpdate);
            
            // 只是插入对象的话,等同于realm.copyToRealm(bean);
            realm.insert(bean);
            // 也是等同于realm.copyToRealmOrUpdate(bean);
            realm.insertOrUpdate(bean);
            // 两者之间的不同是,一个有持久层的返回,一个void,所以需要根据实际的使用来选择
            
            for (RealmFriendBean realmFriendBean : rrlist) {
                // 创建或更新数据库,并返回持久层
                RealmFriendBean update = realm.copyToRealmOrUpdate(realmFriendBean);
                update.setLastMessage("hello");
                Logger.i(update.getId() + "");
                // 将持久层对象存入另一个集合
                aalist.add(update);
            }

            for (RealmFriendBean realmFriendBean : aalist) {
                // 这个集合的对象是持久层对象,所以可以直接操作数据库,但是必须在事务中操作!!
                realmFriendBean.setLastMessage("bye!!!!");
                SystemClock.sleep(5);
                realmFriendBean.setLastTime(System.currentTimeMillis());
            }
        }
    });
    
    // 查询一个不存在的对象,返回值为null
    RealmFriendBean realmFriendBean = realm.where(RealmFriendBean.class).equalTo("id", 99999).findFirst();
    if (realmFriendBean != null) {
        Logger.d(realmFriendBean);
    }
    // realmFriendBean: null
    Logger.e("realmFriendBean: " + realmFriendBean);

    
    // 第一个参数 排序依据的字段,必填 , 第二个参数 默认为ASCENDING升序,可以不填为空, DESCENDING 降序
    RealmResults<RealmFriendBean> all = realm.where(RealmFriendBean.class).findAll().sort("lastTime", Sort.DESCENDING);
    // 或者直接返回时就排好序
    RealmResults<RealmFriendBean> all = realm.where(RealmFriendBean.class).findAllSorted("lastTime", Sort.DESCENDING);
    // ID为5-6之间的
    RealmResults<RealmFriendBean> all = realm.where(RealmFriendBean.class).between("id", 5, 6).findAllSorted("lastTime", Sort.DESCENDING);
    Log.e("size: " , all.size() + "");
    if (all.size() != 0) {
        Log.e("all: ", all.toString());
    }
}

事务的标准写法

  • 查询不需要事务,增删改才需要
Realm realm = Realm.getDefaultInstance();
try {
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            // 增删改
        }
    });
} catch (Exception e) {
    e.printStackTrace();
} finally {
    realm.close();
}
  • minSdkVersion >= 19 and Java >= 7 这样写 无需手动关闭Realm实例
try (Realm realm = Realm.getDefaultInstance()) {
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            // 增删改
        }
    });
} catch (Exception e) {
    e.printStackTrace();
} 
  • executeTransaction的异步方法是executeTransactionAsync
  • executeTransactionAsync有四个重载的方法,第二个参数可以接受一个失败或者成功的回调,也可以三个参数,第二和第三个参数分别接受一个成功的回调和一个失败的回调

executeTransactionAsync方法

主键自增

  • 写在Application类里面
  • AtomicLong是个原子变量,线程安全,非常适合在这个场景里使用
  • 既能保证主键的唯一性,又含有获取和计算同时操作的方法,比如我们这里需要用到的自增并获取
    // player表主键,全局变量
    public static AtomicLong playerInfoPrimaryKeyValue;
    
    @Override
    public void onCreate() {
        super.onCreate();

        // Realm 初始化
        // Call `Realm.init(Context)` before creating a RealmConfiguration
        Realm.init(mContext);
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name(mRealmName).build();
        Realm.setDefaultConfiguration(realmConfiguration);

        // 不能自动增长的主键,所以要记录下
        Realm realm = Realm.getDefaultInstance();
        // 先查表,查到现在主键的最大ID数
        Number playerId = realm.where(RealmPlayerInfo.class).max("playerId");
        playerInfoPrimaryKeyValue = new AtomicLong(playerId == null ? 0 : playerId.longValue());
        // 用完一定要关闭,最好还是try起来
        realm.close();
    }
  • 使用主键
  • incrementAndGet()方法为自增并获取
RealmFriendBean friendBean = realm.createObject(RealmFriendBean.class, playerInfoPrimaryKeyValue.incrementAndGet());

RealmFriendBean bean = new RealmFriendBean();
bean.setId(playerInfoPrimaryKeyValue.incrementAndGet());

重要提示

  • 创建的Realm对象,必须在同一个线程内使用,否则会抛异常
  • 比如在主线线程new的Realm对象就不可以在子线程中使用,反之同理;
  • 不支持嵌套事务(transaction),使用嵌套事务会导致抛出异常;
  • 注意生命周期,防止内存溢出,Activity和fragment中如要多次调用,可以在onDestory()中销毁;

传送门

  • 只罗列了一些简单的用法,Realm的功能非常丰富,包括支持加密和Json的存储这些实用功能
  • 最新版的文档(英文)
  • 最新中文文档(官方只翻译了2.1.0版本的)