Realm 是我見過的說明文檔寫得比較齊全的第三方數(shù)據(jù)庫(kù)框架种蝶,早期的版本中,還有對(duì)應(yīng)的中文版說明文檔,截止當(dāng)前,realm的java版本Latest版本為:1.2.0.
官網(wǎng)傳送門:https://realm.io
Getting Started
一、project level的build.gradle添加如下內(nèi)容
buildscript {
repositories { jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:1.2.0"
}
}
二、在application level#build.gradle中添加以下內(nèi)容
apply plugin: 'realm-android'
你可以在以下地方看到這兩個(gè)例子
Project level build.gradle
Application level build.gradle
以上呜袁,刷新你的gradle依賴,realm就簡(jiǎn)單的被集成成功了.
Models的創(chuàng)建
要自定義創(chuàng)建Models,必須繼承RealmObject類
public class User extends RealmObject {
/**public或protected 也可以*/
private String name;
private int age;
// Standard getters & setters generated by your IDE…
}
屬性支持
Realm 支持以下屬性類型
- boolean
- byte
- short
- int
- long
- float
- double
- String
- Date
- byte[]
------------------------其中---------------------------
byte/short/int/long在Realm中是以long的形式保存的蛉迹,而包裝類型 - Boolean
- Byte
- Short
- Integer
- Long
- Float
- Double
亦可在Realm中使用傅寡,只不過使用封裝類型,屬性值可能被設(shè)置成空.
@Required注解
在某些應(yīng)用場(chǎng)合,空值時(shí)不被允許的北救,這時(shí)候可以使用@Required注解告訴Realm去檢查荐操,禁止空值的出現(xiàn),當(dāng)然主鍵以及RealmList默認(rèn)自帶@Required注解(隱必需)
@Ignore注解
@Ignore可以告訴Realm 對(duì)特定的參數(shù)取消系列化珍策,持有該注解的參數(shù)不會(huì)被持久化到數(shù)據(jù)庫(kù)中.
自動(dòng)更新持久化對(duì)象
RealmObject對(duì)象數(shù)據(jù)發(fā)生改變時(shí)無需用戶去刷新,Realm會(huì)自動(dòng)更新對(duì)象的值
realm.executeTransaction(new Realm.Transaction() {
@Override public void execute(Realm realm) {
Dog myDog = realm.createObject(Dog.class);
myDog.setName("Fido"); myDog.setAge(1);
}
});
Dog myDog = realm.where(Dog.class).equalTo("age",1).findFirst();
realm.executeTransaction(new Realm.Transaction() {
@Override public void execute(Realm realm) {
Dog myPuppy=realm.where(Dog.class).equalTo("age",1).findFirst();
myPuppy.setAge(2);
}
});
myDog.getAge(); // => 2
@Index注解 為表添加索引
使用@Index可以為表中的屬性添加索引托启,使用@Index注解的后果是:
- 它會(huì)使Insert操作更耗時(shí),并且數(shù)據(jù)文件更大
- 查詢更快
所以在適當(dāng)?shù)那闆r下攘宙,為了優(yōu)化讀取性能屯耸,建議使用@Index索引,當(dāng)然使用索引的屬性類型最好是String/byte/short/int/long/boolean/Date中的一種蹭劈。
數(shù)據(jù)庫(kù)升級(jí)(數(shù)據(jù)庫(kù)遷移)
當(dāng)我們使用數(shù)據(jù)庫(kù)時(shí)疗绣,無時(shí)不刻要應(yīng)對(duì)數(shù)據(jù)庫(kù)模型的變化,Realm的數(shù)據(jù)庫(kù)模型用標(biāo)準(zhǔn)的java對(duì)象來定義铺韧,改變數(shù)據(jù)模型只需要改變JAVA數(shù)據(jù)對(duì)象定義多矮。
如果不存在舊的數(shù)據(jù)庫(kù),那么代碼的改變會(huì)立即反應(yīng)到數(shù)據(jù)庫(kù)上哈打,但是如果已經(jīng)有舊版本數(shù)據(jù)庫(kù)文件存在塔逃,Realm會(huì)拋出異常提示數(shù)據(jù)庫(kù)需要升級(jí),此時(shí)請(qǐng)?jiān)?RealmConfiguration 設(shè)置 schema 版本和 migration 代碼來正確處理并避免該異常拋出料仗。
RealmConfiguration config = newRealmConfiguration.Builder(context)
.schemaVersion(2) // 當(dāng)數(shù)據(jù)庫(kù)發(fā)生改變時(shí)湾盗,Version必須增加
.migration(new MyMigration()) // 執(zhí)行數(shù)據(jù)庫(kù)升級(jí)、而不是拋異常
.build()
MyMigration 數(shù)據(jù)庫(kù)升級(jí)操作 例子
RealmMigration migration = new RealmMigration() {
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
// DynamicRealm exposes an editable schema
RealmSchema schema = realm.getSchema();
// Migrate to version 1: Add a new class
// Example:
// public Person extends RealmObject {
// private String name;
// private int age;
// // getters and setters left out for brevity
// }
if (oldVersion == 0) {
schema.create("Person")
.addField("name", String.class)
.addField("age", int.class);
oldVersion++;
}
// Migrate to version 2: Add a primary key + object references
// Example:
// public Person extends RealmObject {
// private String name;
// @PrimaryKey
// private int age;
// private Dog favoriteDog;
// private RealmList<Dog> dogs;
// // getters and setters left out for brevity
// }
if (oldVersion == 1) {
schema.get("Person") .addField("id",
long.class,FieldAttribute.PRIMARY_KEY)
.addRealmObjectField("favoriteDog", schema.get("Dog"))
.addRealmListField("dogs", schema.get("Dog"));
oldVersion++;
}
}
}
如果以上的例子看得不過癮立轧,你也可以直接參考官方提供的
數(shù)據(jù)遷移例子
當(dāng)然格粪,如果舊數(shù)據(jù)庫(kù)不存在的情況下,數(shù)據(jù)庫(kù)遷移(我更喜歡叫它數(shù)據(jù)庫(kù)更新)就沒必要了氛改,而數(shù)據(jù)庫(kù)存在的情況下匀借,如果你不關(guān)心舊數(shù)據(jù)庫(kù)的數(shù)據(jù)丟失,那么也可以這樣做
RealmConfiguration config = new RealmConfiguration.Builder(context)
.deleteRealmIfMigrationNeeded() .build()
以上的配置平窘,當(dāng)發(fā)現(xiàn)數(shù)據(jù)庫(kù)需要更新的時(shí)候,Realm會(huì)自動(dòng)把原來的數(shù)據(jù)庫(kù)(.realm文件)刪除并重新創(chuàng)建,不過這種方式比較適合開發(fā)初期.
數(shù)據(jù)寫入
數(shù)據(jù)庫(kù)的訪問及查詢可以在任何時(shí)間進(jìn)行操作(讀取事務(wù)是隱式的凳怨,無需用戶進(jìn)行聲明)瑰艘,但是數(shù)據(jù)庫(kù)的寫入(比如增刪改)則需要用戶聲明一個(gè)Write事務(wù)是鬼,并將所有操作包含在Write事務(wù)中,事務(wù)可以被提交也可以被取消紫新,當(dāng)事務(wù)提交時(shí)均蜜,只有所有的更改都成功持久化后,事務(wù)提交才會(huì)成功芒率,當(dāng)事務(wù)被取消時(shí)囤耳,所有的更改將被丟棄.使用寫入事務(wù),可以保證數(shù)據(jù)的一致性.
事務(wù)是線程安全的.
// Obtain a Realm instance
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
//... add or update objects here ...
realm.commitTransaction();
當(dāng)在你的業(yè)務(wù)邏輯過程中偶芍,需要取消更改充择,你可以使用:
realm.beginTransaction();
User user = realm.createObject(User.class);
// ...
realm.cancelTransaction();
需要說明的是,寫入事務(wù)之間會(huì)相互阻塞匪蟀,如果一個(gè)寫入事務(wù)正在執(zhí)行椎麦,那么其他線程的寫入事務(wù)就會(huì)阻塞它所在的線程,(同時(shí)在UI線程及后臺(tái)線程開啟事務(wù)有可能導(dǎo)致ANR的問題產(chǎn)生)【TODO 寫入事務(wù)是否最好都移動(dòng)到后臺(tái)線程上去執(zhí)行?】官方提供建議使用 異步事務(wù)(async transactions)方法以避免阻塞 UI 線程.
創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象的方法
一、通過Realm實(shí)例化對(duì)象
realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();
二材彪、 realm.copyToRealm() 添加
User user = new User("John");
user.setEmail("john@corporation.com");
// Copy the object to Realm. Any further changes must happen on realmUser
realm.beginTransaction();
User realmUser = realm.copyToRealm(user);
realm.commitTransaction();
事務(wù)執(zhí)行
除了手動(dòng)調(diào)用realm.beginTransaction()观挎、realm.commitTransaction()和
realm.cancelTransaction()方法之外,只用 [realm.executeTransaction()](https://realm.io/cn/docs/java/latest/api/io/realm/Realm.html#executeTransaction(io.realm.Realm Transaction)) 會(huì)自動(dòng)處理事務(wù)的開始于提交段化,并在錯(cuò)誤的時(shí)候嘁捷,取消事務(wù).
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User user = realm.createObject(User.class);
user.setName("John");
user.setEmail("john@corporation.com");
}
});
異步事務(wù)(Asynchronous Transactions)
使用事務(wù)的時(shí)候,因?yàn)槭聞?wù)的處理是不定時(shí)的显熏,在UI線程上雄嚣,很容易造成應(yīng)用ANR,在此官方文檔建議我們使用異步事務(wù)佃延,耗時(shí)的操作放到后臺(tái)線程去處理现诀,處理結(jié)果通過回調(diào)返回給UI線程
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm bgRealm) {
User user = bgRealm.createObject(User.class);
user.setName("John");
user.setEmail("john@corporation.com");
}}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
// Transaction was a success.
}}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
// Transaction failed and was automatically canceled.
}
});
更新字符串及byte數(shù)組
Realm的寫操作針對(duì)是的整個(gè)屬性,而非屬性中的某一個(gè)字符履肃,如果你有這樣的需求仔沿,請(qǐng)操作一下的例子:
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
bytes[] bytes = realmObject.binary; bytes[4] = 'a'; realm.binary =bytes;
}
});
查詢
查詢條件
Realm 支持以下查詢條件:
between()、greaterThan()尺棋、lessThan()封锉、greaterThanOrEqualTo()
和 lessThanOrEqualTo()
equalTo()和 notEqualTo()
contains()、beginsWith()和 endsWith()
isNull() 和 isNotNull()
isEmpty()和 isNotEmpty()
并非所有條件都適用于所有數(shù)據(jù)類型膘螟,具體請(qǐng)參考 RealmQuery
API成福。
Notifications
Listener只工作于 Looper 線程。對(duì)于非 Looper 線程請(qǐng)使用
Realm.watitForChange().
當(dāng)后臺(tái)線程向 Realm 添加數(shù)據(jù)荆残,你的 UI 線程或者其它線程可以添加一個(gè)監(jiān)聽器來獲取數(shù)據(jù)改變的通知奴艾。監(jiān)聽器在 Realm 數(shù)據(jù)改變的時(shí)候會(huì)被觸發(fā)。
public class MyActivity extends Activity {
private Realm realm; private RealmChangeListener realmListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
realm = Realm.getDefaultInstance();
reamlListener = new RealmChangeListener<Realm>() {
@Override
public void onChange(Realm realm) {
// ... do something with the updates (UI, etc.) ...
}};
realm.addChangeListener(realmListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Remove the listener.
realm.removeChangeListener(realmListener);
// Close the Realm instance.
realm.close();
}}
除了在 Realm實(shí)例上添加監(jiān)聽器以外内斯,你還可以在 RealmObject和 RealmResults實(shí)例上添加監(jiān)聽器蕴潦。你可以通過這樣的方式來監(jiān)視對(duì)象和查詢結(jié)果的改變像啼。另外,當(dāng)監(jiān)聽回調(diào)函數(shù)被調(diào)用時(shí)潭苞,相應(yīng)的數(shù)據(jù)已經(jīng)被更新忽冻,你不需要去做刷新操作。
public class MyActivity extends Activity {
private Realm realm;
private RealmChangeListener puppiesListener;
private RealmChangeListener dogListener;
private RealmResults<Dog> puppies;
private Dog dog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
realm = Realm.getDefaultInstance();
puppiesListener = new
RealmChangeListener<RealmResults<Dog>>() {
@Override
public void onChange(RealmResults<Dog> puppies) {
// ... do something with the updated puppies instance
}};
// Find all the puppies
puppies = realm.where(Dog.class).lessThanOrEqualTo("age", 2).findAll();
puppies.addChangeListener(puppiesListener);
dogListener = new RealmChangeListener<Dog>() {
@Override
public void onChange(Dog dog) {
// ... do something with the updated Dog instance
}};
dog = realm.where(Dog.class).equals("name", "Fido").findFirst();
dog.addChangeListener(dogListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Remove the listeners
puppies.removeChangeListener(puppiesListener);
dog.removeChangeListener(dogListener);
// Close the Realm instance.
realm.close();
}}
最后此疹,這些監(jiān)聽器同樣會(huì)在監(jiān)聽對(duì)象的引用對(duì)象改變時(shí)被觸發(fā)僧诚,請(qǐng)見示例:
Person person = realm.where(Person.class).findFirst();person.getDogs();
// => 2 - Assume there are 2 dogs in the list
person.addChangeListener(new RealmChangeListener<Person>() {
@Override
public void onChange(Person person) {
// React to the change in the Person instance.
// This will also get called when any referenced dogs are updated.
} });
Dog dog = person.getDogs().get(0);
realm.beginTransaction();
dog.setAge(5);realm.commitTransaction();
// Person change listener is called on the next iteration of the run loop because
// a referenced dog object changed.
NEXT 等待補(bǔ)充中....