Realm使用學(xué)習(xí)筆記

Realm介紹與引入

其實(shí)Realm也已經(jīng)作為移動(dòng)端數(shù)據(jù)庫被使用也有一段時(shí)間了具则,而如果作為新手想要把App中數(shù)據(jù)存儲(chǔ)到本地即纲,可能我們File、SP博肋、SQLite低斋,今天要講的Realm就是代替的SQLite的方法之一,當(dāng)然還有GreenDao等等匪凡,我知道Realm是七月底的時(shí)候膊畴,各個(gè)公眾號(hào)開始介紹和使用它,而我開始使用它卻是從上周才開始的病游。

我在開始學(xué)習(xí)Realm的時(shí)候就是一口氣把官方的文檔看完唇跨,而現(xiàn)在最新的版本是2.2.1稠通,官方文檔也會(huì)有中文的比如2.1.1,所以我覺得大家可以一邊看英文的一邊看中文的买猖,還能鍛煉自己的英文閱讀能力改橘,畢竟Android官方文檔大部分都是英文的,所以在學(xué)習(xí)新技術(shù)的時(shí)候就可以看得出英文閱讀能力到底有多重要玉控。 下面就開始我們Realm的使用之旅吧飞主!

不過所有這種第三方的開源庫使用的第一步都是先添加依賴,然后開始使用高诺。

1.在整個(gè)項(xiàng)目的build.gradle下的dependencies添加:
???? classpath "io.realm:realm-gradle-plugin:2.2.0"
2.在app目錄下的build.gradle添加:
???? apply plugin: 'realm-android'

Realm基礎(chǔ)

接下來在使用之前我們可以先來看一些基礎(chǔ)概念:
1.比如我們?nèi)绾味x一個(gè)數(shù)據(jù)模型碌识,我們可以自定義一個(gè)類繼承RealmObject或者實(shí)現(xiàn)RealmModel接口并在類上面添加@RealmClass這個(gè)注解,這時(shí)我們table就會(huì)在運(yùn)行時(shí)自動(dòng)創(chuàng)建了虱而,代碼如下:

public class TestModel extends RealmObject{
        ...
} 
or
@RealmClass
public class OtherTestModel implements RealmModel{
        ...
}

當(dāng)我們點(diǎn)進(jìn)RealmObject時(shí)會(huì)發(fā)現(xiàn)其實(shí)它也是實(shí)現(xiàn)RealmModel接口的筏餐,如圖:


RealmObject.png

2.我們創(chuàng)建了數(shù)據(jù)模型后還需要添加字段,這樣才能真的組成一個(gè)table薛窥,Realm支持的類型如下:boolean胖烛、byte、int诅迷、long佩番、float、double(以及他們的封裝類)罢杉、String趟畏、Date、byte[]滩租、RealmObject赋秀、RealmList<? extends RealmObject>,不過成員變量的修飾符并沒有限制律想。

3.一些屬性:

  • 主鍵 @PrimaryKey猎莲,但是Realm不支持自增長(zhǎng)的主鍵,我一般使用的時(shí)候都是定義一個(gè)String類型的主鍵技即,然后通過UUID保證主鍵的唯一性(如果封裝類作為主鍵著洼,主鍵可為null,除非同時(shí)被非空修飾)而叼。
  • 非空 @Required
  • 忽略 @Ignore 如果該類中的某個(gè)字段被它修飾了就表明它不會(huì)被保存到Realm中身笤。
  • 索引 @Index 為字段增加搜索索引,這會(huì)導(dǎo)致插入速度變慢葵陵,同時(shí)數(shù)據(jù)文件體積有所增加液荸,但能加速查詢。

Realm使用

那接下來我們就可以開始使用Realm了脱篙,在代碼中使用Realm前還需要對(duì)它進(jìn)行初始化Realm.init(上下文對(duì)象);我是在全局的Application類中就行的娇钱,代碼如下

public class MyApplication extends Application {   
  private static Context mContext;    
  @Override    
  public void onCreate() {        
        mContext = getApplicationContext();        
        Realm.init(mContext);    
    }    
    public static Context getContext() {        
        return mContext;    
    }
}

然后再在清單文件中聲明一下就可以了

<application    
   android:allowBackup="true"    
    ... 
    android:name=".MyApplication">
        ...
</application>    

1.準(zhǔn)備

//  創(chuàng)建實(shí)體類  該類必須包含一個(gè)無參構(gòu)造
public class TestModel extends RealmObject{    
    @PrimaryKey    
    private String _id;    
    private String testTitle;    
    private String updateTime;
    ...
}

//  如下配置的 Realm 會(huì)被存儲(chǔ)在 Context.getFilesDir() 并且命名為 default.realm
//  獲取Realm實(shí)例 獲取默認(rèn)配置的Realm
Realm mRealm = Realm.getDefaultInstance();

//  事務(wù) 無論是增刪改查都需要開啟事務(wù)
mRealm.beginTransaction();
//  具體邏輯
...
mRealm .commitTransaction();
//  如果要取消事務(wù)的話
mRealm .cancelTransaction();

//  為result設(shè)置數(shù)據(jù)改變偵聽  賦值的話我是先調(diào)用查詢 查詢就算沒有條目也不會(huì)返回null伤柄,所以無須擔(dān)心
mResults.addChangeListener(new RealmChangeListener<RealmResults<TestModel>>() {    
    @Override    
    public void onChange(RealmResults<TestModel> element) {        
        //  這里無需再次賦值給RealmResults, 因?yàn)樗麜?huì)自動(dòng)更新值(必須要當(dāng)前前程有Looper, 而當(dāng)前是主線程)       
        mResults = element;        
        mAdapter.notifyDataSetChanged();    
     }
});

2.寫入

/**     
 * 插入假數(shù)據(jù) 這種方式會(huì)產(chǎn)生默認(rèn)值的對(duì)象,然后手動(dòng)設(shè)置值,且如果有主鍵時(shí)需要在createObject中設(shè)置 在后臺(tái)線程進(jìn)行     
 */    
private void createItemData() {        
    //  executeTransaction系列方法都會(huì)自動(dòng)管理事務(wù) 開啟,關(guān)閉文搂,取消     
    mRealm.executeTransactionAsync(new Realm.Transaction() {    
        @Override            
        public void execute(Realm realm) {                
            UUID uuid = UUID.randomUUID();   
            //  寫入的時(shí)候指明了Id             
            TestModel testModel = realm.createObject(TestModel.class, uuid.toString());                
            testModel.setTestTitle("點(diǎn)擊編輯標(biāo)題");
            testModel.setUpdateTime(getCurrTime());            
        }        
    }, new Realm.Transaction.OnSuccess() {            
         @Override            
         public void onSuccess() {
             mAdapter.notifyDataSetChanged();            
        }        
    }, new Realm.Transaction.OnError() {            
        @Override            
        public void onError(Throwable error) {               
             Log.e("Realm", "保存失敗" + error.getMessage());            
        }        
    });    
}

//  插入的話還有另一種方法copyToRealm();
//  這個(gè)Dog對(duì)象只是一個(gè)普通的對(duì)象
Dog dog = new Dog();
dog.setName("Rex");
dog.setAge(1);
mRealm.beginTransaction();
//  而這邊返回的是managedDog 才是被持久化的對(duì)象
final managedDog = realm.copyToRealm(dog);
mRealm.commitTransaction();

3.查詢

//  查詢所有  TestModel是我自己寫的類
RealmResults<TestModel> mResults = mRealm.where(TestModel.class).findAllAsync();

/** 
 * 根據(jù)標(biāo)題查詢數(shù)據(jù) 在UI線程進(jìn)行 
 */
private void queryResultByTitle(String title) {  
    //  根據(jù)Title進(jìn)行模糊查詢  
    mResults = mRealm.where(TestModel.class).contains("testTitle", title)            .findAll();    
    mAdapter.notifyDataSetChanged();
}


//  支持的查詢的條件  當(dāng)然也支持聚合函數(shù)
- between()响迂、greaterThan()、lessThan()细疚、greaterThanOrEqualTo() 和 lessThanOrEqualTo()  
- equalTo() 和 notEqualTo()  
- contains()、beginsWith()和 endsWith()  (類似模糊查尋)
- isNull() 和 isNotNull()
- isEmpty() 和 isNotEmpty()

//  每個(gè)查詢條件都會(huì)被被隱式地被邏輯和(&)組合在一起川梅,而邏輯或(or)需要顯式地去執(zhí)行 or()  如下:
RealmResults<User> r = realm.where(User.class)
            .greaterThan("age", 10) //implicit AND 
            .beginGroup() 
                .equalTo("name", "Peter")
                 .or() 
                .contains("name", "Jo") 
            .endGroup()
            .findAll();

//  排序
RealmResults<User> result = realm.where(User.class).findAll();
result = result.sort("age");  //  默認(rèn)正序
result = result.sort("age", Sort.DESCENDING);

4.刪除

/** 
 * 刪除數(shù)據(jù) 在后臺(tái)線程進(jìn)行 
 */
private void deleteItemData(final int index) {
    mRealm.executeTransaction(new Realm.Transaction() {        
        @Override        
        public void execute(Realm realm) {
            mResults.deleteFromRealm(index);        
        }    
    });
}

//  刪除的方法還有很多就不一一列舉了

5.更新

/**
 * 更新數(shù)據(jù)方式一 通過再次查詢 在后臺(tái)線程進(jìn)行
 */
private void updateItemDataById(final String title) {
    mRealm.executeTransactionAsync(new Realm.Transaction() {
        @Override        
        public void execute(Realm realm) {
            TestModel testModel = realm.where(TestModel.class).equalTo("_id", mCurrEditId).findFirst();            
            testModel.setUpdateTime(getCurrTime());            testModel.setTestTitle(title);        
        }    
    }, new Realm.Transaction.OnSuccess() {        
        @Override        
        public void onSuccess() {            
            mAdapter.notifyDataSetChanged();        
        }    
    }, new Realm.Transaction.OnError() {        
        @Override        
        public void onError(Throwable error) {            
            Log.e("Realm", "保存失敗" + error.getMessage());        
        }    
    });
}

/**
 * 更新數(shù)據(jù)方法二 通過Realm的特性(實(shí)時(shí)更新) 在創(chuàng)建RealmResults的線程進(jìn)行   
 */
private void updateItemData(final String title) {
    mRealm.executeTransaction(new Realm.Transaction() {        
        @Override        
        public void execute(Realm realm) {
            mResults.get(mCurrItemIndex).setTestTitle(title);
            mResults.get(mCurrItemIndex).setUpdateTime(getCurrTime());
        }    
    });    
    mAdapter.notifyDataSetChanged();
}

6.數(shù)據(jù)庫配置

//  Realm的配置類
RealmConfiguration config = new RealmConfiguration.Builder()
            .name("test.realm")     //  命名      
            .schemaVersion(3)      //  數(shù)據(jù)庫版本        
            .migration(new MyMigration())    //  數(shù)據(jù)庫內(nèi)容發(fā)生變化    
            .build();
//  獲取Realm對(duì)象并手動(dòng)設(shè)置配置
mRealm = Realm.getInstance(config);

/**
 * 當(dāng)我們更新數(shù)據(jù)庫字段時(shí)會(huì)使用這個(gè)類
 */
public class MyMigration implements RealmMigration {    
    @Override    
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {        
        RealmSchema schema = realm.getSchema();        
        //  比如當(dāng)老的版本為3的時(shí)候        
        if (oldVersion == 3) {            
              schema.get("TestModel")                    
                      //  添加新的Realm支持的字段
                      .addField("testBassType", int.class)                    
                      //  添加新的自定義對(duì)象
                      .addRealmObjectField("testRealmObject", schema.get("OtherTestModel"))                    
                      //  添加新的List對(duì)象疯兼,用于一對(duì)多 多對(duì)多
                      .addRealmListField("testRealmList", schema.get("OtherTestModel"));            
                      oldVersion++;        
        }    
    }
}

//  而我在相應(yīng)的類中已經(jīng)寫了
//  用于測(cè)試數(shù)據(jù)庫字段變更 版本變成4的時(shí)候放開下面的字段
//    public int testBassType;
//    public OtherTestModel testRealmObject;
//    public RealmList<OtherTestModel> testRealmList;

7.釋放資源

@Override
protected void onDestroy() {    
    super.onDestroy();    
    //  移除偵聽 并關(guān)閉Realm    
    mResults.removeChangeListeners();    
    mRealm.close();}

Realm知識(shí)點(diǎn)補(bǔ)充

1.異步查詢可寫回調(diào)的偵聽,且其回調(diào)是通過Looper被執(zhí)行的(如寫入那條)贫途。

2.Realm的實(shí)體類必須要包含一個(gè)無參構(gòu)造函數(shù)吧彪,如果不寫任何構(gòu)造,Java自帶一個(gè)無參構(gòu)造丢早,若是自己寫了其他參數(shù)的構(gòu)造后無參構(gòu)造會(huì)不可用姨裸,此時(shí)需要手動(dòng)頭添加一個(gè)。

3.主鍵不支持自增長(zhǎng)怨酝。

4.使用查詢后的所返回的RealmResults<自定義類>對(duì)象列表傀缩,里面的對(duì)象并非是拷貝,而是查詢后匹配對(duì)象的引用农猬,所以刪改都可以直接用它來操作赡艰。

5.每個(gè)查詢條件都會(huì)被被隱式地被邏輯和(&)組合在一起,而邏輯或(or)需要顯式地去執(zhí)行 or()斤葱。

6.異步操作可以對(duì)RealmResults設(shè)置addChangeLintener(Callback)慷垮,偵聽結(jié)果集發(fā)生的變化,記得最后要移除掉偵聽揍堕。

7.異步查詢可用isLoaded()檢查是否加載完畢料身,而同步時(shí)該方法永遠(yuǎn)返回true。

8.Realm衩茸、RealmObject 和RealmResults 實(shí)例都不可以跨線程使用芹血,而獲取后都是獲取當(dāng)前線程的實(shí)例,跨線程使用會(huì)報(bào)錯(cuò)递瑰。

9.Realm實(shí)例是基于引用計(jì)數(shù)的祟牲,所以你在同一個(gè)線程中獲取了幾次實(shí)例,也需要相應(yīng)的close()幾次抖部。

10.如果Realm實(shí)例存在于一個(gè)帶有Looper的線程说贝,那么這個(gè)Realm實(shí)例就具有自動(dòng)刷新的功能,這個(gè)時(shí)候就可以使用慎颗,且Listener只工作于 Looper線程乡恕。

11.如果Realm實(shí)例所在的線程沒有Looper言询,則更新需要你手動(dòng)調(diào)用waitForChange()。

我希望可以站在初學(xué)者&自學(xué)者的角度把Android中的知識(shí)點(diǎn)很清楚的介紹給大家傲宜,希望大家喜歡运杭。 如果有錯(cuò)誤希望指出來,有問題或者沒看懂函卒,都可以來問我的

    項(xiàng)目代碼的地址:https://github.com/GzwJaaaelu/RealmDemo
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辆憔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子报嵌,更是在濱河造成了極大的恐慌虱咧,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锚国,死亡現(xiàn)場(chǎng)離奇詭異腕巡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)血筑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門绘沉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豺总,你說我怎么就攤上這事车伞。” “怎么了喻喳?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵帖世,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我沸枯,道長(zhǎng)日矫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任绑榴,我火速辦了婚禮哪轿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翔怎。我一直安慰自己窃诉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布赤套。 她就那樣靜靜地躺著飘痛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪容握。 梳的紋絲不亂的頭發(fā)上宣脉,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音剔氏,去河邊找鬼塑猖。 笑死竹祷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的羊苟。 我是一名探鬼主播塑陵,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蜡励!你這毒婦竟也來了令花?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤凉倚,失蹤者是張志新(化名)和其女友劉穎彭则,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體占遥,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年输瓜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓦胎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尤揣,死狀恐怖搔啊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情北戏,我是刑警寧澤负芋,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站嗜愈,受9級(jí)特大地震影響旧蛾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蠕嫁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一锨天、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剃毒,春花似錦病袄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至基公,卻和暖如春幅慌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轰豆。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國打工欠痴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迄靠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓喇辽,卻偏偏與公主長(zhǎng)得像掌挚,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子菩咨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容