在 Android 开发中, 经常会用到数据库操作, 各种增删改查语句, 烦不胜烦. 今天介绍一款好用的数据库 Realm, 可以让数据库操作更加便捷.
一, 目录
二, Realm 简介
数据库 Realm, 是用来替代 SQLite 的一种解决方案, 它有一套自己的数据库存储引擎, 比 SQLite 更轻量级, 拥有更快的速度, 并且具有很多现代数据库的特性, 比如支持 JSON, 流式 API, 数据变更通知, 自动数据同步, 简单身份验证, 访问控制, 事件处理, 最重要的是跨平台, 目前已有 Java,Objective C,Swift,React-Native,Xamarin 这五种实现.
优势
易用
Ream 不是在 SQLite 基础上的 ORM, 它有自己的数据查询引擎. 并且十分容易使用.
快速
由于它是完全重新开始开发的数据库实现, 所以它比任何的 ORM 速度都快很多, 甚至比 SLite 速度都要快.
跨平台
Realm 支持 iOS & OS X (ObjectiveC & Swift) & Android. 我们可以在这些平台上共享 Realm 数据库文件, 并且上层逻辑可以不用任何改动的情况下实现移植.
高级
Ream 支持加密, 格式化查询, 易于移植, 支持 JSON, 流式 API, 数据变更通知等高级特性
可视化
Realm 还提供了一个轻量级的数据库查看工具, 在 Mac Appstore 可以下载 "Realm Browser" 这个工具, 开发者可以查看数据库当中的内容, 执行简单的插入和删除数据的操作.
三, 环境配置
(1) 在项目的 build 文件加上
- buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath "io.realm:realm-gradle-plugin:3.0.0"
- }
- }
(2) 在 App 的 build 文件加上
apply plugin: 'realm-android'
四, 初始化 Realm
(1) 在 Application 的 oncreate()方法中 Realm.init()
- public class MyApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- Realm.init(this);
- }
- }
(2)在 Application 的 oncreate()方法中对 Realm 进行相关配置
1使用默认配置
- public class MyApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- // The Realm file will be located in Context.getFilesDir() with name "default.realm"
- Realm.init(this);
- RealmConfiguration config = new RealmConfiguration.Builder().build();
- Realm.setDefaultConfiguration(config);
- }
- }
2使用自定义配置
- public class MyApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- Realm.init(this);
- RealmConfiguration config = new RealmConfiguration.Builder()
- .name("myRealm.realm")
- .deleteRealmIfMigrationNeeded()
- .build();
- Realm.setDefaultConfiguration(config);
- }
- }
(3)在 AndroidManifest.xml 配置自定义的 Application
- <application
- Android:name=".MyApplication"
- ...
- />
五, 创建实体
(1)新建一个类继承 RealmObject
- public class TimeInfo extends RealmObject {
- // 年月日信息
- private String ymD;
- // 标题
- private String title;
- // 内容
- private String content;
- // 时间段信息 12:00-13:00
- @PrimaryKey
- private String addTime;
- // 创建该条目时的时间
- private String createTime;
- // 是否是新的任务
- private boolean isNew = true;
- // 在列表中所处位置
- private int position = -1;
................ 省略 get,set 方法
}
(2)其他相关说明
1, 支持的数据类型:
boolean, byte, short, int, long, float, double, String, Date and byte[]
在 Realm 中 byte, short, int, long 最终都被映射成 long 类型
2, 注解说明
@PrimaryKey
1字段必须是 String, integer,byte,short, int,long 以及它们的封装类 Byte, Short, Integer, and Long
2使用了该注解之后可以使用 copyToRealmOrUpdate()方法, 通过主键查询它的对象, 如果查询到了, 则更新它, 否则新建一个对象来代替.
3使用了该注解将默认设置 (@index) 注解
4使用了该注解之后, 创建和更新数据将会慢一点, 查询数据会快一点.
@Required
数据不能为 null
@Ignore
忽略, 即该字段不被存储到本地
@Index
为这个字段添加一个搜索引擎, 这将使插入数据变慢, 数据增大, 但是查询会变快. 建议在需要优化读取性能的情况下使用.
六, 增删改查
1. 增
1)实现方法一: 事务操作
- mRealm.beginTransaction();
- TimeInfo info= realm.createObject(TimeInfo.class); // Create a new object
- info.setTitle("realm");
- realm.commitTransaction();
2)实现方法二: 使用事务块
- mRealm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- realm.copyToRealm(bean);
- }
- });
2. 查
(1)查询全部
RealmResults<? extends RealmObject> beans = mRealm.where(clazz).findAll();
(2)条件查询
RealmObject bean = mRealm.where(clazz).equalTo(fieldName, value).findFirst();
常见的条件如下(详细资料请查官方文档):
- between(), greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
- equalTo() & notEqualTo()
- contains(), beginsWith() & endsWith()
- isNull() & isNotNull()
- isEmpty() & isNotEmpty()
(3)对查询结果进行排序
- RealmResults<? extends RealmObject> beans = mRealm.where(clazz).findAll();
- // 升序排序
- RealmResults<? extends RealmObject> results = beans.sort(fieldName, Sort.ASCENDING);
- // 降序排序
- RealmResults<? extends RealmObject> results = beans.sort(fieldName, Sort.DESCENDING);
(4)其他查询
sum,min,max,average 只支持整型数据字段
- /**
- * 查询最大位置
- */
- private void getMaxPosition(){
- Number max= mRealm.where(TimeInfo.class).findAll().max("position");
- int maxPosition=max.intValue();
- }
其他使用类似
3. 删
- mRealm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- // 删除第一个数据
- beans.deleteFirstFromRealm();
- // 删除最后一个数据
- beans.deleteLastFromRealm();
- // 删除某个位置的数据
- beans.deleteFromRealm(position);
- // 删除所有数据
- beans.deleteAllFromRealm();
- }
- });
4. 改
- TimeInfo info= mRealm.where(TimeInfo.class).equalTo("position", position).findFirst();
- mRealm.beginTransaction();
- info.setPosition(newPosition);
- mRealm.commitTransaction();
七, 异步操作
大多数情况下, Realm 的增删改查操作足够快, 可以在 UI 线程中执行操作. 但是如果遇到较复杂的增删改查, 或增删改查操作的数据较多时, 就可以子线程进行操作.
(1)异步增:
- RealmAsyncTask addTask= mRealm.executeTransactionAsync(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- realm.copyToRealm(bean);
- }
- }, new Realm.Transaction.OnSuccess() {
- @Override
- public void onSuccess() {
- ToastUtil.showShortToast(mContext,"添加成功");
- }
- }, new Realm.Transaction.OnError() {
- @Override
- public void onError(Throwable error) {
- ToastUtil.showShortToast(mContext,"添加失败");
- }
- });
(2)异步删
- RealmAsyncTask deleteTask= mRealm.executeTransactionAsync(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- TimeInfo info =realm.where(TimeInfo.class).equalTo("position",position).findFirst();
- info .deleteFromRealm();
- }
- }, new Realm.Transaction.OnSuccess() {
- @Override
- public void onSuccess() {
- ToastUtil.showShortToast(mContext,"删除成功");
- }
- }, new Realm.Transaction.OnError() {
- @Override
- public void onError(Throwable error) {
- ToastUtil.showShortToast(mContext,"删除失败");
- }
- });
(3)异步改
- RealmAsyncTask updateTask= mRealm.executeTransactionAsync(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- TimeInfo info =realm.where(TimeInfo.class).equalTo("position",position).findFirst();
- info .setPosition(position);
- }
- }, new Realm.Transaction.OnSuccess() {
- @Override
- public void onSuccess() {
- ToastUtil.showShortToast(mContext,"更新成功");
- }
- }, new Realm.Transaction.OnError() {
- @Override
- public void onError(Throwable error) {
- ToastUtil.showShortToast(mContext,"失败成功");
- }
- });
(4)异步查
- RealmResults<TimeInfo> infos=mRealm.where(TimeInfo.class).findAllAsync();
- infos.addChangeListener(new RealmChangeListener<RealmResults<TimeInfo>>() {
- @Override
- public void onChange(RealmResults<TimeInfo> element) {
- // 执行接收到查询结果数据
- }
- });
注意: findAllAsync()立刻返回结果, 结果为空. 可以添加监听, 当返回的结果集合 infos 变化时, 会调用该方法.
最后在销毁 Activity 或 Fragment 时, 要取消掉异步任务, 以及取消监听.
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (updateTask!=null&&!addTask.isCancelled()){
- updateTask.cancel();
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- infos.removeChangeListeners();
- }
最后别忘了关掉 Realm, 防止内存泄漏.
mRealm.close();
八, 封装使用
定义一个 RealmOperationHelper 类, 里面封装各种增删改查方法, 方便我们直接调用.
首先, 把 RealmOperationHelper 设置为单例模式, 使用静态内部类的方式.
- private static Realm mRealm;
- private static class SingletonHolder {
- private static RealmOperationHelper INSTANCE = new RealmOperationHelper(
- mRealm);
- }
- private RealmOperationHelper(Realm realm) {
- this.mRealm = realm;
- }
- /**
- * 获取 RealmOperation 的单例
- *
- * @param realm 传入 realm 实例对象
- * @return 返回 RealmOperation 的单例
- */
- public static RealmOperationHelper getInstance(Realm realm) {
- if (realm != null) {
- mRealm = realm;
- }
- return SingletonHolder.INSTANCE;
- }
封装各种增删改查操作, 包括同步与异步. 异步操作中, 对 onSuccess,onError 方法回调的没有进行处理, 实用性不好, 后面进一步考虑.
使用实例:
增
RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).add(info);
删
RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).deleteElement(TimeInfo.class,curPosition);
异步查
- final RealmResults<TimeInfo> results = (RealmResults<TimeInfo>) RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).queryAllAsync(TimeInfo.class);
- results.addChangeListener(new RealmChangeListener<RealmResults<TimeInfo>>() {
- @Override
- public void onChange(RealmResults<TimeInfo> element) {
- // 只要 results 改变就会回调, 及时取消监听
- results.removeAllChangeListeners();
- // 获取数据, 更新 UI.
- }
- });
使用效果, 很方便, 很简洁.
Realm 封装工具类地址
自己是从事了七年开发的 Android 工程师, 不少人私下问我, 2019 年 Android 进阶该怎么学, 方法有没有?
没错, 年初我花了一个多月的时间整理出来的学习资料, 希望能帮助那些想进阶提升 Android 开发, 却又不知道怎么进阶学习的朋友.[包括高级 UI, 性能优化, 架构师课程, NDK,Kotlin, 混合式开发(ReactNative+Weex),Flutter 等架构技术资料] , 希望能帮助到您面试前的复习且找到一个好的工作, 也节省大家在网上搜索资料的时间来学习.
来源: http://www.jianshu.com/p/e9f495819a24