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
- 支援預設型別boolean, short, ìnt, long, float, double, String, Date , byte[]
- RealmObject
- 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;
}
}