深刻解析Sqlite的完美替代者,android數據庫新王者——Realm

寫在前面:html

又到一年一度七夕虐狗節,看着你們忍受着各類朋友圈和QQ空間還有現實生活中的輪番轟炸,我實在不忍心再在這裏給你們補刀,因此我以爲今天不虐狗,繼續給你們分享有用的。java

 

若是你比較關心android開發的最新動態的話,我想你必定知道android數據庫新王者,沒錯,就是這個東西——Realm。android

在安卓開發中,咱們有sharedPreference和文件操做,固然還有一直爲之自豪的輕量級數據庫sqlite。git

SharedPreference實際上是採用xml的方式,以鍵值對形式存儲基本數據類型的數據,對於複雜的數據篩選查詢操做,file和sharedpreference就顯得雞肋,這個時候sqlite即可以知足有大量複雜查詢要求的緩存數據操做,可是它的使用一直被人詬病,是的,由於代碼量太多了!github

做爲一個要爲全世界作貢獻的程序猿,怎麼能夠忍受這樣多的代碼實現一點小東西呢?No,No,咱們絕對不能接受!!!sql

還好網上出現了不少優秀的ORM框架供咱們參略,好比ORMite,greenDao等,而這些都是基於SQLite的。數據庫

額,仍是不扯遠了,直接給你們帶來今天的主角,沒錯,就是它——realm!緩存

 

對於初學Realm的小夥伴,確定仍是應該對比着咱們熟悉不過的sqlite來講的。網絡

相比sqlite,Realm具備別人不可比擬的神奇速度,哦,這不是重點,它還有強大先進的特性等着你,好比數據加密支持,對Json的支持,流暢的API,數據觀察者變化,全部的一切都是爲了讓咱們程序猿更加瀟灑!什麼?程序猿還能夠瀟灑??有的小夥伴確定怒火中燒了?樓主別裝逗比。app

額,好吧,只要你心瀟灑,你人就瀟灑啦~怎麼跑題了呢?仍是迴歸正題!!!

哦,對了,對於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)來作。當數據庫的數據有變化時,系統會自動回調此方法,說到這裏,小夥伴是否是心動了?在列表數據的時候,麻麻不再用擔憂我忘了更新數據庫了。

 

注:此文章爲原創,歡迎轉載,請在文章頁面明顯位置給出此文連接:http://www.cnblogs.com/liushilin/p/5752099.html若您以爲這篇文章還不錯請點擊下右下角的推薦,很是感謝!

相關文章
相關標籤/搜索