Sqlite的完美替代者,android数据库新王者——Realm

2024-06-09 13:32

本文主要是介绍Sqlite的完美替代者,android数据库新王者——Realm,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址    http://www.cnblogs.com/liushilin/p/5752099.html;


自己记录一下,有时间去看看。mark;

如果你比较关心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,无法编译别怪楼主没提醒你哈!!

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

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

1 apply plugin: 'realm-android'

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

复制代码
 1 package com.example.nanchen.realmdemo;
 2 
 3 import io.realm.RealmObject;
 4 import io.realm.annotations.Ignore;
 5 import io.realm.annotations.PrimaryKey;
 6 import io.realm.annotations.Required;
 7 
 8 /**
 9  *
10  * @author nanchen
11  * @date  2016-08-08  17:21:15
12  */
13 public class User extends RealmObject {
14     //主键必须添加注解
15     @PrimaryKey
16     private int id;//主键id
17     @Required    //注解设为Required代表必须项
18     private String name;//姓名
19 
20     private int age;//年龄
21 
22     @Ignore   //表示忽视项,数据库不会存储该字段
23     private boolean hasGrilFriend;//是否有女朋友
24 
25     public User() {
26     }
27 
28     public User(int id, String name, int age) {
29         this.id = id;
30         this.name = name;
31         this.age = age;
32     }
33 
34     public User(String name, int id, int age, boolean hasGrilFriend) {
35         this.name = name;
36         this.id = id;
37         this.age = age;
38         this.hasGrilFriend = hasGrilFriend;
39     }
40 
41     public boolean isHasGrilFriend() {
42         return hasGrilFriend;
43     }
44 
45     public void setHasGrilFriend(boolean hasGrilFriend) {
46         this.hasGrilFriend = hasGrilFriend;
47     }
48 
49     public int getId() {
50         return id;
51     }
52 
53     public void setId(int id) {
54         this.id = id;
55     }
56 
57     public String getName() {
58         return name;
59     }
60 
61     public void setName(String name) {
62         this.name = name;
63     }
64 
65     public int getAge() {
66         return age;
67     }
68 
69     public void setAge(int age) {
70         this.age = age;
71     }
72 
73     @Override
74     public String toString() {
75         return "User{" +
76                 "id=" + id +
77                 ", name='" + name + '\'' +
78                 ", age=" + age +
79                 ", hasGrilFriend=" + hasGrilFriend +
80                 '}';
81     }
82 }
复制代码

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

复制代码
 1 package com.example.nanchen.realmdemo;
 2 
 3 import android.content.Context;
 4 
 5 import io.realm.Realm;
 6 import io.realm.RealmConfiguration;
 7 
 8 /**
 9  * @author nanchen
10  * @date 16-8-8 下午5:51
11  */
12 public class RealmUtils {
13     private Context context;
14     private static RealmUtils mInstance;
15     private String realName = "myRealm.realm";
16 
17     private RealmUtils(Context context){
18         this.context = context;
19     }
20 
21     public static RealmUtils getInstance(Context context){
22         if (mInstance == null){
23             synchronized (RealmUtils.class){
24                 if (mInstance == null){
25                     mInstance = new RealmUtils(context);
26                 }
27             }
28         }
29         return mInstance;
30     }
31 
32     /**
33      * 获得Realm对象
34      * @return
35      */
36     public Realm getRealm(){
37         return Realm.getInstance(new RealmConfiguration.Builder(context).name(realName).build());
38     }
39 }
复制代码

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

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

复制代码
 1 package com.example.nanchen.realmdemo;
 2 
 3 import java.sql.SQLException;
 4 import java.util.List;
 5 
 6 /**
 7  * 操作数据库的接口Dao
 8  *
 9  * @author  nanchen
10  * @date   2016-08-08  17:23:18
11  *
12  */
13 public interface UserDao {
14 
15     /**
16      * 插入一个用户
17      * @param user    需要插入的用户对象
18      * @throws SQLException
19      */
20     void insert(User user) throws SQLException;
21 
22     /**
23      * 获得所有的用户列表
24      * @return 用户列表
25      * @throws SQLException
26      */
27     List<User> getAllUser() throws SQLException;
28 
29     /**
30      * 更新一个用户
31      * @param user 需要更新的用户类
32      * @return      更新后的对象
33      * @throws SQLException
34      */
35     User updateUser(User user) throws SQLException;
36 
37     /**
38      * 根据姓名修改新姓名
39      * @param name1 老名字
40      * @param name2 新名字
41      * @throws SQLException
42      */
43     void updateUser(String name1,String name2) throws SQLException;
44 
45     /**
46      * 根据id删除用户
47      * @param id 用户主键
48      * @throws SQLException
49      */
50     void deleteUser(int id) throws SQLException;
51 
52     /**
53      * 异步添加用户
54      * @param user 需要添加的用户对象
55      * @throws SQLException
56      */
57     void insertUserAsync(User user) throws SQLException;
58 
59     /**
60      * 按名字或者年龄查找第一个User
61      */
62     User findByNameOrAge(String name1,int age1) throws SQLException;
63 
64     /**
65      * 清楚所有
66      * @throws SQLException
67      */
68     void deleteAll() throws SQLException;
69 
70     /**
71      * 关闭事务
72      */
73     void closeRealm();
74 }
复制代码

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

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

复制代码
  1 package com.example.nanchen.realmdemo;
  2 
  3 import android.content.Context;
  4 
  5 import java.sql.SQLException;
  6 import java.util.List;
  7 
  8 import io.realm.Realm;
  9 import io.realm.Realm.Transaction;
 10 import io.realm.RealmResults;
 11 import io.realm.Sort;
 12 
 13 /**
 14  * @author nanchen
 15  * @date 16-8-8 下午5:49
 16  */
 17 public class UserDaoImpl implements UserDao {
 18 
 19     private Context context;
 20     private Realm mRealm;
 21 
 22     public UserDaoImpl(Context context) {
 23         mRealm = RealmUtils.getInstance(context).getRealm();
 24     }
 25 
 26     /**
 27      * 同步插入
 28      * @param user    需要插入的用户对象
 29      * @throws SQLException
 30      */
 31     @Override
 32     public void insert(User user) throws SQLException {
 33         mRealm.beginTransaction();//必须先开启事务
 34         User user1 = mRealm.copyToRealm(user);//把User对象复制到Realm
 35         mRealm.commitTransaction();//提交事务
 36 //        mRealm.close();//必须关闭,不然会造成内存泄漏
 37     }
 38 
 39     /**
 40      * 返回所有的User对象,并按照名字首字母排序
 41      * @return  User对象表
 42      * @throws SQLException
 43      */
 44     @Override
 45     public List<User> getAllUser() throws SQLException {
 46         List<User> list = null;
 47         RealmResults<User> results = mRealm.where(User.class).findAll();
 48         results.sort("name", Sort.DESCENDING);//针对字符串的排序,但目前并不是支持所有字符集
 49         list = results;
 50 //        mRealm.close();
 51         return list;
 52     }
 53 
 54     /**
 55      * 更新一个User
 56      * @param user 需要更新的用户类
 57      * @return 返回更新后的User
 58      * @throws SQLException
 59      */
 60     @Override
 61     public User updateUser(User user) throws SQLException {
 62         mRealm.beginTransaction();//开启事务
 63         User user1 = mRealm.copyToRealmOrUpdate(user);
 64         mRealm.commitTransaction();//提交事务
 65 //        mRealm.close();//必须关闭事务
 66         return user1;
 67     }
 68 
 69     /**
 70      * @param name1 老名字
 71      * @param name2 新名字
 72      * @throws SQLException
 73      */
 74     @Override
 75     public void updateUser(String name1, String name2) throws SQLException {
 76         mRealm.beginTransaction();//开启事务
 77         mRealm.where(User.class)
 78                 .equalTo("name",name1)//查询出name为name1的User对象
 79                 .findFirst()
 80                 .setName(name2);//修改查询出的第一个对象的名字
 81         mRealm.commitTransaction();
 82 //        mRealm.close();
 83     }
 84 
 85     /**
 86      * 根据id删除一个User
 87      * @param id 用户主键
 88      * @throws SQLException
 89      */
 90     @Override
 91     public void deleteUser(int id) throws SQLException {
 92         User user = mRealm.where(User.class).equalTo("id",id).findFirst();//删除id列值为id的行
 93         mRealm.beginTransaction();
 94         user.deleteFromRealm();//从数据库删除
 95         mRealm.commitTransaction();
 96 //        mRealm.close();
 97     }
 98 
 99     /**
100      * 异步插入User
101      * @param user 需要添加的用户对象
102      * @throws SQLException
103      */
104     @Override
105     public void insertUserAsync(final User user) throws SQLException {
106         //一个Realm只能在同一个线程访问,在子线程中进行数据库操作必须重新获取realm对象
107         mRealm.executeTransaction(new Transaction() {
108             @Override
109             public void execute(Realm realm) {
110                 realm.beginTransaction();//开启事务
111                 User user1 = realm.copyToRealm(user);
112                 realm.commitTransaction();
113                 realm.close();//记得关闭事务
114             }
115         });
116 //        mRealm.close();//外面也不能忘记关闭事务
117     }
118 
119 
120     /**
121      * 返回第一个指定名字或者年龄的对象
122      * @param name1 名字
123      * @param age1  年龄
124      */
125     @Override
126     public User findByNameOrAge(String name1,int age1) throws SQLException{
127         User user = mRealm.where(User.class)
128                 .equalTo("name",name1)//相当于where name = name1
129                 .or()//或,连接查询条件,没有这个方式时会默认是&连接
130                 .equalTo("age",age1)//相当于where age = age1
131                 .findFirst();
132         //整体相当于select * from (表名) where name = (传入的name) or age = (传入的age)limit 1;
133 //        mRealm.close();
134         return user;
135     }
136 
137     @Override
138     public void deleteAll() throws SQLException {
139         mRealm.beginTransaction();
140         mRealm.where(User.class).findAll().deleteAllFromRealm();
141         mRealm.commitTransaction();
142 //        mRealm.close();
143     }
144 
145 
146     @Override
147     public void closeRealm() {
148         mRealm.close();
149     }
150 }
复制代码

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

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

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

复制代码
 1 package com.example.nanchen.realmdemo;
 2 
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.util.Log;
 6 
 7 import java.sql.SQLException;
 8 
 9 public class MainActivity extends AppCompatActivity {
10     private UserDao userDao;
11 
12     @Override
13     protected void onCreate(Bundle savedInstanceState) {
14         super.onCreate(savedInstanceState);
15         setContentView(R.layout.activity_main);
16 
17         userDao = new UserDaoImpl(this);
18         try {
19             userDao.deleteAll();//先删除所有,以免demo出现主键已经存在的异常
20             User user = new User();
21             user.setId(10);
22             user.setName("小刺猬");
23             user.setAge(22);
24             user.setHasGrilFriend(true);
25             userDao.insert(user);
26 
27             Log.d("flag","插入小刺猬----"+userDao.getAllUser().toString());
28 
29             for (int i = 0; i < 5; i++) {
30                 userDao.insert(new User(i,"南尘"+i,20+i));
31             }
32             Log.d("flag","插入5个对象----"+userDao.getAllUser().toString());
33             Log.d("flag","查询1----"+userDao.findByNameOrAge("南尘1",20));
34             Log.d("flag","查询2----"+userDao.findByNameOrAge("南尘1",23));
35             userDao.updateUser("南尘1","nanchen");
36             Log.d("flag","更新1----"+userDao.findByNameOrAge("南尘1",23));
37             userDao.deleteUser(0);//删除0
38             Log.d("flag","删除后查看----"+userDao.getAllUser().toString());
39 
40 
41             //统一关闭事务
42             userDao.closeRealm();
43         } catch (SQLException e) {
44             e.printStackTrace();
45         }
46     }
47 }
复制代码

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)来做。当数据库的数据有变化时,系统会自动回调此方法,说到这里,小伙伴是不是心动了?在列表数据的时候,麻麻再也不用担心我忘了更新数据库了。

这篇关于Sqlite的完美替代者,android数据库新王者——Realm的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1045318

相关文章

关于如何更好管理好数据库的一点思考

本文尝试从数据库设计理论、ER图简介、性能优化、避免过度设计及权限管理方面进行思考阐述。 一、数据库范式 以下通过详细的示例说明数据库范式的概念,将逐步规范化一个例子,逐级说明每个范式的要求和变换过程。 示例:学生课程登记系统 初始表格如下: 学生ID学生姓名课程ID课程名称教师教师办公室1张三101数学王老师101室2李四102英语李老师102室3王五101数学王老师101室4赵六103物理陈

数据库期末复习知识点

A卷 1. 选择题(30') 2. 判断范式(10') 判断到第三范式 3. 程序填空(20') 4. 分析填空(15') 5. 写SQL(25') 5'一题 恶性 B卷 1. 单选(30') 2. 填空 (20') 3. 程序填空(20') 4. 写SQL(30') 知识点 第一章 数据库管理系统(DBMS)  主要功能 数据定义功能 (DDL, 数据定义语

给数据库的表添加字段

周五有一个需求是这样的: 原来数据库有一个表B,现在需要添加一个字段C,我把代码中增删改查部分进行了修改, 比如insert中也添入了字段C。 但没有考虑到一个问题,数据库的兼容性。因为之前的版本已经投入使用了,再升级的话,需要进行兼容处理,当时脑子都蒙了,转不过来,后来同事解决了这个问题。 现在想想,思路就是,把数据库的表结构存入文件中,如xxx.sql 实时更新该文件: CREAT

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。

移动硬盘盒:便携与交互的完美结合 PD 充电IC

在数字化时代的浪潮中,数据已成为我们生活中不可或缺的一部分。随着数据的不断增长,人们对于数据存储的需求也在不断增加。传统的存储设备如U盘、光盘等,虽然具有一定的便携性,但在容量和稳定性方面往往难以满足现代人的需求。而移动硬盘,以其大容量、高稳定性和可移动性,成为了数据存储的优选方案。然而,单纯的移动硬盘在携带和使用上仍存在诸多不便,于是,移动硬盘盒应运而生,以其独特的便携性和交互性,成为了数据存储