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

来源:互联网 发布:手机工作记录软件 编辑:程序博客网 时间:2024/05/08 04:32

原文地址    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 nanchen11  * @date  2016-08-08  17:21:1512  */13 public class User extends RealmObject {14     //主键必须添加注解15     @PrimaryKey16     private int id;//主键id17     @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     @Override74     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 nanchen10  * @date 16-8-8 下午5:5111  */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      * @return35      */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  nanchen10  * @date   2016-08-08  17:23:1811  *12  */13 public interface UserDao {14 15     /**16      * 插入一个用户17      * @param user    需要插入的用户对象18      * @throws SQLException19      */20     void insert(User user) throws SQLException;21 22     /**23      * 获得所有的用户列表24      * @return 用户列表25      * @throws SQLException26      */27     List<User> getAllUser() throws SQLException;28 29     /**30      * 更新一个用户31      * @param user 需要更新的用户类32      * @return      更新后的对象33      * @throws SQLException34      */35     User updateUser(User user) throws SQLException;36 37     /**38      * 根据姓名修改新姓名39      * @param name1 老名字40      * @param name2 新名字41      * @throws SQLException42      */43     void updateUser(String name1,String name2) throws SQLException;44 45     /**46      * 根据id删除用户47      * @param id 用户主键48      * @throws SQLException49      */50     void deleteUser(int id) throws SQLException;51 52     /**53      * 异步添加用户54      * @param user 需要添加的用户对象55      * @throws SQLException56      */57     void insertUserAsync(User user) throws SQLException;58 59     /**60      * 按名字或者年龄查找第一个User61      */62     User findByNameOrAge(String name1,int age1) throws SQLException;63 64     /**65      * 清楚所有66      * @throws SQLException67      */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      * 异步插入User101      * @param user 需要添加的用户对象102      * @throws SQLException103      */104     @Override105     public void insertUserAsync(final User user) throws SQLException {106         //一个Realm只能在同一个线程访问,在子线程中进行数据库操作必须重新获取realm对象107         mRealm.executeTransaction(new Transaction() {108             @Override109             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     @Override126     public User findByNameOrAge(String name1,int age1) throws SQLException{127         User user = mRealm.where(User.class)128                 .equalTo("name",name1)//相当于where name = name1129                 .or()//或,连接查询条件,没有这个方式时会默认是&连接130                 .equalTo("age",age1)//相当于where age = age1131                 .findFirst();132         //整体相当于select * from (表名) where name = (传入的name) or age = (传入的age)limit 1;133 //        mRealm.close();134         return user;135     }136 137     @Override138     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     @Override147     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     @Override13     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);//删除038             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)来做。当数据库的数据有变化时,系统会自动回调此方法,说到这里,小伙伴是不是心动了?在列表数据的时候,麻麻再也不用担心我忘了更新数据库了。

0 0
原创粉丝点击