Realm

Realm是一個手機的資料庫lib, 支援Android, iOS。
較以往的ORM不同, 使用了自有的引擎去取代SQlite

特有的RealmResults繼承了AbstractList去override常用的
get(index), size(), add(), addAll(), remove(), clear()...
並增加了sort(), sum()...
使用zero-copy & lazy 技術大大提升效能

參考文件

ref link
realm https://realm.io/
github https://github.com/realm/realm-java/
document https://realm.io/docs/java/latest/

如何使用

1.gradle

compile 'io.realm:realm-android:0.81.1'

2.configuration

realmConfiguration = new RealmConfiguration
                .Builder(this)
                .name(account)//如果你想設置個別資料庫名稱
                .encryptionKey(key)//如果你需要加密的話
                .build();

3.getInstance

//default 
realm = Realm.getInstance(Context);

//use configuration
realm = Realm.getInstance(realmConfiguration);

4.onDestory

@Override
protected void onDestroy() {
    super.onDestroy();
    realm.close();
}

5.建立Realm Model

  1. 支援預設型別boolean, short, ìnt, long, float, double, String, Date , byte[]
  2. RealmObject
  3. RealmList<? extends RealmObject>

要存入的Object只能以上這幾種,如果要存入自定義型別,必須extands RealmObject

public class User extends RealmObject {

    @PrimaryKey
    private String           name;
    private int              age;
    private RealmList<User>  friends;

    @Ignore
    private int              sessionId;

    }
}

@PrimaryKey 顧名思義
@Ignore 不會存入資料庫的成員變數
@Index 可以加快Query的速度,但相對的insert會變得緩慢

6.Write

為了Thread safety,每當從Realm取得的資料要修改刪除時,必須...

realm.beginTransaction();
//... 寫這裡 ...
realm.commitTransaction();

也許你想修改資料,但此時並不想commit進去,你可以...

realm.beginWriteTransaction();
//... 寫這裡 ...
realm.cancelTransaction();

或是...

 realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        User user = realm.createObject(User.class);
        user.setName("Cuber");
        user.setAge(26);
    }
});

存入一個RealmObject

realm.beginTransaction();
Person person = realm.createObject(Person.class);
person.setName("Cuber");
person.setAge(26);
realm.commitTransaction();

存入一個RealmList

realm.beginTransaction();
realm.copyToRealm(friendList);
realm.commitTransaction();

如果你有設@PrimaryKey, 就可以針對key做update

realm.beginTransaction();
realm.copyToRealmOrUpdate(friendList);
realm.commitTransaction();

注意
1.必須在你getInstance的那條Thread做Write
2.Realm存入的都是以RealmObject為單位,所以如果寫入了person, friendList後
當你下query Person.class的時候這會把所有的Person都會被抓出

7.Queries

先where到你要的class

RealmQuery<User> query = realm.where(User.class);

在下條件給他

query.equalTo("name", "John");
        query.or().equalTo("name", "Peter");

// Execute the query:
RealmResults<User> result1 = query.findAll();

// Or alternatively do the same all at once (the "Fluent interface"):
RealmResults<User> result2 = realm.where(User.class)
        .equalTo("name", "John")
        .or()
        .equalTo("name", "Peter")
        .findAll();
  • between()
  • greaterThan()
  • lessThan()
  • greaterThanOrEqualTo()
  • lessThanOrEqualTo()
  • equalTo()
  • notEqualTo()
  • contains()
  • beginsWith()
  • endsWith()
All fetches (including queries) are lazy in Realm, and the data is never copied.

常常我們會從資料庫取得資料,然後Display在UI上,
但礙於Realm的限制,我們無法從background Thread去Query,然後再到uiThread去Diaplay
但其實Realm也沒有必要這麼做,建議暫時都讓query都在uiThread上吧!
(已試過100000筆資料測試)

8.Sorting

很簡單,看就知道了

RealmResults<User> result = realm.where(User.class).findAll();
result.sort("age"); // 升冪
result.sort("age", RealmResults.SORT_ORDER_DESCENDING);// 降冪

9.Chaining Queries

有三種取得方式

  • findFirst() //第一筆
  • findAll() // 全部
  • findAllSorted() // 排序後的全部

10.Aggregation

還有4個很方便的方法

long   sum     = result.sum("age").longValue();
long   min     = result.min("age").longValue();
long   max     = result.max("age").longValue();
double average = result.average("age");
  • sum()
  • min()
  • max()
  • average()

11.Deletion

// All changes to data must happen in a transaction
realm.beginTransaction();

// remove single match
result.remove(0);
result.removeLast();

// remove a single object
Dog dog = result.get(5);
dog.removeFromRealm();

// Delete all matches
result.clear();

realm.commitTransaction();

12.Gson

相信很多人的專案裡都有用到Gson這個Lib
但當你的model在extends RealmObject時,如果用Gson去做Parse,就會發生錯誤
在文件中提供了下面這個方法

Gson gson = new GsonBuilder()
        .setExclusionStrategies(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return f.getDeclaringClass().equals(RealmObject.class);
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        })
        .create();

而且在你的model不需要在標上 @SerializedName

13.心得

雖然Query的時候速度非常的快,但是write的時候就會明顯感覺到時間Delay
所以建議在Query資料的時候在uiThread上,而在write的時候轉換到backgroundThread去
提供一種寫法如下...

/* 以fragment為例 */

public class RealmFragment extends Fragment implements Handler.Callback {

private RealmConfiguration realmConfiguration;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    /* Realm */
    realmConfiguration = new RealmConfiguration
            .Builder(this)
            .build();
    realm = Realm.getInstance(realmConfiguration);

    /* start */
    backgroundHandler.sendEmptyMessage(MSG_QUERY_DATA);
}

@Override
public boolean handleMessage(Message msg) {

    if (!isAdded()) return false;

    switch(msg.what){

        case MSG_QUERY_DATA:

            // 從網路抓取資料
            Response response = client.newCall(request).execute();

            // 傳回 uiThread 做UI更新
            Message respMsg = uiHandler.obtainMessage();
            respMsg.what = MSG_DISPLAY_DATA;
            respMsg.obj = response;
            backgroundHandler.sendMessage(respMsg);
            break;

        case MSG_DISPLAY_DATA:

            Response apiResponse = (Response)msg.obj;

            // 失敗
            if(null == apiResponse){
                // show error
            }

            // 成功
            else{
               // display data on UI
            }

            break;

        case MSG_WANT_TO_SAVE_DATA_TO_REALM:

            /* 當你想要存入Realm的時候 */
            backgroundHandler.sendEmptyMessage(MSG_SAVE_REALM);

            break;

        case MSG_SAVE_REALM:

            /* 切換到background去操作Realm */
            realm = Realm.getInstance(realmConfiguration);

            realm.beginTransaction();
            realm.copyToRealmOrUpdate(dataList);
            realm.commitTransaction();

            break;

        return false;
    }
}

results matching ""

    No results matching ""