写在前面:

又到一年一度七夕虐狗节,看着大家忍受着各种朋友圈和QQ空间还有现实生活中的轮番轰炸,我实在不忍心再在这里给大家补刀,所以我觉得今天不虐狗,继续给大家分享有用的。

如果你比较关心android开发的最新动态的话,我想你一定知道android数据库新王者,没错,就是这个东西——Realm。

在安卓开发中,我们有sharedPreference和文件操作,当然还有一直为之自豪的轻量级数据库sqlite。

SharedPreference其实是采用xml的方式,以键值对形式存储基本数据类型的数据,对于复杂的数据筛选查询操作,file和sharedpreference就显得鸡肋,这个时候sqlite便可以满足有大量复杂查询要求的缓存数据操作,但是它的使用一直被人诟病,是的,因为代码量太多了!

作为一个要为全世界做贡献的程序猿,怎么可以忍受这样多的代码实现一点小东西呢?No,No,我们绝对不能接受!!!

还好网上出现了很多优秀的ORM框架供我们参略,比如ORMite,greenDao等,而这些都是基于SQLite的。

额,还是不扯远了,直接给大家带来今天的主角,没错,就是它——realm!

对于初学Realm的小伙伴,肯定还是应该对比着我们熟悉不过的sqlite来说的。

相比sqlite,Realm具有别人不可比拟的神奇速度,哦,这不是重点,它还有强大先进的特性等着你,比如数据加密支持,对Json的支持,流畅的API,数据观察者变化,所有的一切都是为了让我们程序猿更加潇洒!什么?程序猿还可以潇洒??有的小伙伴肯定怒火中烧了?楼主别装逗比。

额,好吧,只要你心潇洒,你人就潇洒啦~怎么跑题了呢?还是回归正题!!!

哦,对了,对于Realm,有一个非常强大的东西,就是它可以和当前最主流的网络框架Retrofit以及强大的异步框架Rxjava联用哦,对于Retrofit的介绍可以去直通车:

http://www.cnblogs.com/liushilin/p/5680135.html

等等,怎么总感觉少说了点什么,额,对,如标题一样,它还有一个很强大的特性,那就是它可以总能获取到最新的数据,是的,它是一个live db~~

额,还是说说怎么使用吧,更具体的可以看官方API频道:https://realm.io/docs/java/latest/

1)首先在你的project的gradle文件中添加这样一句,注意:是工程gradle,不是app的gradle,无法编译别怪楼主没提醒你哈!!

 classpath 'io.realm:realm-gradle-plugin:1.1.0'

2)然后再去app下的gradle头部添加:

 apply plugin: 'realm-android'

3)随便写一个Java实体类,例如我写了一个用户类User,只需要继承RealmObject即可,对于主键可以添加注解@PrimaryKey,对于@Required自然是必填项,@Ignore即是可忽略的。

 package com.example.nanchen.realmdemo;

 import io.realm.RealmObject;
import io.realm.annotations.Ignore;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required; /**
*
* @author nanchen
* @date 2016-08-08 17:21:15
*/
public class User extends RealmObject {
//主键必须添加注解
@PrimaryKey
private int id;//主键id
@Required //注解设为Required代表必须项
private String name;//姓名 private int age;//年龄 @Ignore //表示忽视项,数据库不会存储该字段
private boolean hasGrilFriend;//是否有女朋友 public User() {
} public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
} public User(String name, int id, int age, boolean hasGrilFriend) {
this.name = name;
this.id = id;
this.age = age;
this.hasGrilFriend = hasGrilFriend;
} public boolean isHasGrilFriend() {
return hasGrilFriend;
} public void setHasGrilFriend(boolean hasGrilFriend) {
this.hasGrilFriend = hasGrilFriend;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} 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;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", hasGrilFriend=" + hasGrilFriend +
'}';
}
}

4)额,这个东西肯定也是需要初始化的嘛。额,楼主这里就单独写一个RealmUtils工具类了。

 package com.example.nanchen.realmdemo;

 import android.content.Context;

 import io.realm.Realm;
import io.realm.RealmConfiguration; /**
* @author nanchen
* @date 16-8-8 下午5:51
*/
public class RealmUtils {
private Context context;
private static RealmUtils mInstance;
private String realName = "myRealm.realm"; private RealmUtils(Context context){
this.context = context;
} public static RealmUtils getInstance(Context context){
if (mInstance == null){
synchronized (RealmUtils.class){
if (mInstance == null){
mInstance = new RealmUtils(context);
}
}
}
return mInstance;
} /**
* 获得Realm对象
* @return
*/
public Realm getRealm(){
return Realm.getInstance(new RealmConfiguration.Builder(context).name(realName).build());
}
}

5)然后在看看基本操作,楼主这里就使用比较流行的Dao模式吧

先写一个Dao接口,注释很清楚哈。

 package com.example.nanchen.realmdemo;

 import java.sql.SQLException;
import java.util.List; /**
* 操作数据库的接口Dao
*
* @author nanchen
* @date 2016-08-08 17:23:18
*
*/
public interface UserDao { /**
* 插入一个用户
* @param user 需要插入的用户对象
* @throws SQLException
*/
void insert(User user) throws SQLException; /**
* 获得所有的用户列表
* @return 用户列表
* @throws SQLException
*/
List<User> getAllUser() throws SQLException; /**
* 更新一个用户
* @param user 需要更新的用户类
* @return 更新后的对象
* @throws SQLException
*/
User updateUser(User user) throws SQLException; /**
* 根据姓名修改新姓名
* @param name1 老名字
* @param name2 新名字
* @throws SQLException
*/
void updateUser(String name1,String name2) throws SQLException; /**
* 根据id删除用户
* @param id 用户主键
* @throws SQLException
*/
void deleteUser(int id) throws SQLException; /**
* 异步添加用户
* @param user 需要添加的用户对象
* @throws SQLException
*/
void insertUserAsync(User user) throws SQLException; /**
* 按名字或者年龄查找第一个User
*/
User findByNameOrAge(String name1,int age1) throws SQLException; /**
* 清楚所有
* @throws SQLException
*/
void deleteAll() throws SQLException; /**
* 关闭事务
*/
void closeRealm();
}

然后是我们的Dao实现类,同样是满满的注释,看楼主对你们这么用心,很感动有木有,想以身相许了有木有,额,楼主,不搞基!!!

不过你既然这么心存感激,就在文章右下角给楼主点个赞吧~~嘿嘿。

 package com.example.nanchen.realmdemo;

 import android.content.Context;

 import java.sql.SQLException;
import java.util.List; import io.realm.Realm;
import io.realm.Realm.Transaction;
import io.realm.RealmResults;
import io.realm.Sort; /**
* @author nanchen
* @date 16-8-8 下午5:49
*/
public class UserDaoImpl implements UserDao { private Context context;
private Realm mRealm; public UserDaoImpl(Context context) {
mRealm = RealmUtils.getInstance(context).getRealm();
} /**
* 同步插入
* @param user 需要插入的用户对象
* @throws SQLException
*/
@Override
public void insert(User user) throws SQLException {
mRealm.beginTransaction();//必须先开启事务
User user1 = mRealm.copyToRealm(user);//把User对象复制到Realm
mRealm.commitTransaction();//提交事务
// mRealm.close();//必须关闭,不然会造成内存泄漏
} /**
* 返回所有的User对象,并按照名字首字母排序
* @return User对象表
* @throws SQLException
*/
@Override
public List<User> getAllUser() throws SQLException {
List<User> list = null;
RealmResults<User> results = mRealm.where(User.class).findAll();
results.sort("name", Sort.DESCENDING);//针对字符串的排序,但目前并不是支持所有字符集
list = results;
// mRealm.close();
return list;
} /**
* 更新一个User
* @param user 需要更新的用户类
* @return 返回更新后的User
* @throws SQLException
*/
@Override
public User updateUser(User user) throws SQLException {
mRealm.beginTransaction();//开启事务
User user1 = mRealm.copyToRealmOrUpdate(user);
mRealm.commitTransaction();//提交事务
// mRealm.close();//必须关闭事务
return user1;
} /**
* @param name1 老名字
* @param name2 新名字
* @throws SQLException
*/
@Override
public void updateUser(String name1, String name2) throws SQLException {
mRealm.beginTransaction();//开启事务
mRealm.where(User.class)
.equalTo("name",name1)//查询出name为name1的User对象
.findFirst()
.setName(name2);//修改查询出的第一个对象的名字
mRealm.commitTransaction();
// mRealm.close();
} /**
* 根据id删除一个User
* @param id 用户主键
* @throws SQLException
*/
@Override
public void deleteUser(int id) throws SQLException {
User user = mRealm.where(User.class).equalTo("id",id).findFirst();//删除id列值为id的行
mRealm.beginTransaction();
user.deleteFromRealm();//从数据库删除
mRealm.commitTransaction();
// mRealm.close();
} /**
* 异步插入User
* @param user 需要添加的用户对象
* @throws SQLException
*/
@Override
public void insertUserAsync(final User user) throws SQLException {
//一个Realm只能在同一个线程访问,在子线程中进行数据库操作必须重新获取realm对象
mRealm.executeTransaction(new Transaction() {
@Override
public void execute(Realm realm) {
realm.beginTransaction();//开启事务
User user1 = realm.copyToRealm(user);
realm.commitTransaction();
realm.close();//记得关闭事务
}
});
// mRealm.close();//外面也不能忘记关闭事务
} /**
* 返回第一个指定名字或者年龄的对象
* @param name1 名字
* @param age1 年龄
*/
@Override
public User findByNameOrAge(String name1,int age1) throws SQLException{
User user = mRealm.where(User.class)
.equalTo("name",name1)//相当于where name = name1
.or()//或,连接查询条件,没有这个方式时会默认是&连接
.equalTo("age",age1)//相当于where age = age1
.findFirst();
//整体相当于select * from (表名) where name = (传入的name) or age = (传入的age)limit 1;
// mRealm.close();
return user;
} @Override
public void deleteAll() throws SQLException {
mRealm.beginTransaction();
mRealm.where(User.class).findAll().deleteAllFromRealm();
mRealm.commitTransaction();
// mRealm.close();
} @Override
public void closeRealm() {
mRealm.close();
}
}

6)实际上很多时候我们的close都是写在方法里面的,楼主只是为了测试Demo的好用,就单独写了一个关闭事务的方法来标新立异了哈,大家各自创新~~

额,对了,close你是必须必须调用的,不然你会内存泄漏!!

再简单看一下楼主的调用:

 package com.example.nanchen.realmdemo;

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log; import java.sql.SQLException; public class MainActivity extends AppCompatActivity {
private UserDao userDao; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); userDao = new UserDaoImpl(this);
try {
userDao.deleteAll();//先删除所有,以免demo出现主键已经存在的异常
User user = new User();
user.setId(10);
user.setName("小刺猬");
user.setAge(22);
user.setHasGrilFriend(true);
userDao.insert(user); Log.d("flag","插入小刺猬----"+userDao.getAllUser().toString()); for (int i = 0; i < 5; i++) {
userDao.insert(new User(i,"南尘"+i,20+i));
}
Log.d("flag","插入5个对象----"+userDao.getAllUser().toString());
Log.d("flag","查询1----"+userDao.findByNameOrAge("南尘1",20));
Log.d("flag","查询2----"+userDao.findByNameOrAge("南尘1",23));
userDao.updateUser("南尘1","nanchen");
Log.d("flag","更新1----"+userDao.findByNameOrAge("南尘1",23));
userDao.deleteUser(0);//删除0
Log.d("flag","删除后查看----"+userDao.getAllUser().toString()); //统一关闭事务
userDao.closeRealm();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

7)运行查看结果,好像没啥问题呢。

哈哈,对于Realm的简单使用今天就讲到这里哦,大家赶紧搞定一波学习,有女朋友的陪女朋友去,没女朋友的,赶紧学会了好找女朋友!

项目已同步至:https://github.com/nanchen2251/RealmDemo

额,最后根据Realm类总结一番:

1)Realm类可以对你的持久化对象进行存储和事务管理,可以用来创建RealmObjects实例,并且领域内的对象可以在任何时候查询和读取。

2)修改,插入和删除操作均必须在一个完整的事务中,在更新操作中,我们可以通过copyToRealmOrUpdate来做,但是官方更推荐我们用先查询出来后更新的方法,上面代码也有提到。

3)该事务确保多个实例(在多个线程中)可以在一个一致的状态和保证事务在ACID前提下,访问相同的对象。

4)当一个Realm实例操作完成后,一定一定要记住调用close()方法,否则导致了本地资源无法释放而引起了OOM别怪楼主没提醒。

5)Realm实例不能不在不同的线程间访问操作,所以楼主的异步插入里面打开了一个新的实例,当然也得关掉它!

6)对于UI线程来说。打开和关闭Realm实例,应当放在onCreate/onDestory或者onPause/onStop方法中。

7)在不同的线程间,Realm实例使用Handler机制来调整它的状态。也就是说,Realm实例在线程中,如果没有Looper,是不能收到更新通知的。除非手动调用waitForChange方法。

8)重点注意:Realm数据库的主键字段不是自动增长的,并且不支持设置数据的自增。需要自己设置,做添加的时候如果不给id字段值,默认为是0。后面再添加的话会报错说id为0的字段已经存在。尤其是批量添加的时候要注意,当心出现只添加了一条记录的悲剧!

9)数据自动更新。可以通过调用addChangeListener(context)来做。当数据库的数据有变化时,系统会自动回调此方法,说到这里,小伙伴是不是心动了?在列表数据的时候,麻麻再也不用担心我忘了更新数据库了。

注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接:http://www.cnblogs.com/liushilin/p/5752099.html
若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!

深入解析Sqlite的完美替代者,android数据库新王者——Realm的更多相关文章

  1. 转: app端数据库(性能高) realm (ios, android 均支持)

    转:  http://ios.jobbole.com/85041/ 移动端数据库新王者:realm 2016/05/14 · iOS开发 · 数据库 分享到:0 原文出处: 没故事的卓同学(@没故事的 ...

  2. Android 数据库框架总结(转)

    转自 http://blog.csdn.net/da_caoyuan/article/details/61414626 一:OrmLite 简述: 优点: 1.轻量级:2.使用简单,易上手:3.封装完 ...

  3. Android 数据库框架总结,总有一个适合你!

    一:OrmLite 简述: 优点: 1.轻量级:2.使用简单,易上手:3.封装完善:4.文档全面.缺点:1.基于反射,效率较低(本人还没有觉得效率低):2.缺少中文翻译文档 jar包 地址:http: ...

  4. [Android Pro] 完美Android Cursor使用例子(Android数据库操作)

    reference to : http://www.ablanxue.com/prone_10575_1.html 完美 Android Cursor使用例子(Android数据库操作),Androi ...

  5. Android数据库之SQLite数据库

    Android数据库之SQLite数据库 导出查看数据库文件 在android中,为某个应用程序创建的数据库,只有它可以访问,其它应用程序是不能访问的,数据库位于Android设备/data/data ...

  6. Android数据库高手秘籍(一)——SQLite命令

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/38461239 要想熟练地操作不论什么一个数据库.最最主要的要求就是要懂SQL语言, ...

  7. Android数据库框架——GreenDao轻量级的对象关系映射框架,永久告别sqlite

    Android数据库框架--GreenDao轻量级的对象关系映射框架,永久告别sqlite 前不久,我在写了ORMLite这个框架的博文 Android数据库框架--ORMLite轻量级的对象关系映射 ...

  8. Android数据库(1)、SQLite数据库介绍

    一.关系性数据库   关系型数据库主要有以下三个特征,尤为明显,如果没有这个三个特征约束,当多个客户端使用数据的时候就会出现各种各样的错误,所以关系型数据库定义这些约束,让客户端程序只要遵守这个规则便 ...

  9. Android数据库

    Android数据库 什么情况下我们才用数据库做数据存储? 大量数据结构相同的数据需要存储时.Android内置了sqlite,轻量级. 创建数据库的方法 创建一个类继承SqliteOpenHelpe ...

随机推荐

  1. mysql每秒最多能插入多少条数据 ? 死磕性能压测

    前段时间搞优化,最后瓶颈发现都在数据库单点上. 问DBA,给我的写入答案是在1W(机械硬盘)左右. 联想起前几天infoQ上一篇文章说他们最好的硬件写入速度在2W后也无法提高(SSD硬盘) 但这东西感 ...

  2. JS里面Data日期格式转换

    var format = function(time, format){     var t = new Date(time);     var tf = function(i){return (i  ...

  3. HTML DOM 对象

    本篇主要介绍HTML DOM 对象:Document.Element.Attr.Event等4个对象. 目录 1. Document 对象:表示文档树的根节点,大部分属性和方法都是对元素进行操作. 2 ...

  4. Android GridView 通过seletor 设置状态和默认状态

    Android中可以通过selector控制GridView Item 的状态,而省去使用代码控制 GridView View Selector Xml文件 <?xml version=&quo ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(80)-自由桌面

    系列目录 前言 这次我们来做一个有趣的事情,有朋友跟做了很远,找我要自由桌面的代码,这次我们将演示自由桌面的代码. 自由桌面:用户可以随意增删改桌面的布局.个数(只留自己需要看到的数据),这次纯属Ea ...

  6. [.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office

    打造一个很简单的文档转换器 - 使用组件 Spire.Office [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6024827.html 序 之前,& ...

  7. 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)

    WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...

  8. ASP.NET MVC5----常见的数据注解和验证

    只要一直走,慢点又何妨. 在使用MVC模式进行开发时,数据注解是经常使用的(模型之上操作),下面是我看书整理的一些常见的用法. 什么是验证,数据注解 验证 从全局来看,发现逻辑仅是整个验证的很小的一部 ...

  9. 报错:You need to use a Theme.AppCompat theme (or descendant) with this activity.

    学习 Activity 生命周期时希望通过 Dialog 主题测试 onPause() 和 onStop() 的区别,点击按钮跳转 Activity 时报错: E/AndroidRuntime: FA ...

  10. Linux基础介绍【第二篇】

    远程连接Linux的原理 SHH远程连接介绍 当前,在几乎所有的互联网企业环境中,最常用的Linux提供远程连接服务的工具就是SSH软件,SSH分为SSH客户端和SSH服务端两部分.其中,SSH服务端 ...