前提
Android Studio >= 1.5.1
A recent version of the Android SDK.
JDK version >=7.
支持Api>9的Android版本
環(huán)境配置
Step 1: Add the following class path dependency to the project level build.gradle file.
buildscript {
repositories {
jcenter()
}
dependencies
{
classpath "io.realm:realm-gradle-plugin:2.3.1"
}
}
The project level build.gradle
file is located here:

Step 2: Apply the realm-android
plugin to the top of application level build.gradle
file.
apply plugin: 'realm-android'
The application level build.gradle

Models
Realm model classes are created by extending the RealmObject
base class.
public class User extends RealmObject {
private String name;
private int age;
@Ignore
private int sessionId; // Standard getters & setters generated by your IDE…
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSessionId() {
return sessionId;
}
public void setSessionId(int sessionId) {
this.sessionId = sessionId;
}
}
一個Realm的類支持 public,protected 和 private和自定義方法
public class User extends RealmObject {
public String name;
public boolean hasLongName() {
return name.length() > 7;
}
@Override
public boolean equals(Object o) {
// Custom equals comparison
}
}
Relationships
任意兩個 RealmObjects 可以一起使用
public class Email extends RealmObject {
private String address;
private boolean active; // ... setters and getters left out
}
public class Contact extends RealmObject {
private String name;
private Email email; // ... setters and getters left out
}
多對一
簡單地聲明一個屬性的類型是 RealmObject的子類 :
public class Contact extends RealmObject {
private Email email; // Other fields…
}
每一個contact對象只有0或者1email的實例幌衣,如果設置RealmObject的字段為空稻扬,會把兩個表的關聯(lián)取消会前,但不會刪除相應表的數據
多對多
你可以建立幾個對象和一個對象的關系通過使用RealmList<T> 的字段兵迅。
如下:
public class Contact extends RealmObject {
public String name;
public RealmList<Email> emails;
}
public class Email extends RealmObject {
public String address;
public boolean active;
}
RealmList 基本上是RealmObject的容器蝴光,RealmList就像Java中的List一樣滑蚯【⌒ǎ可以無限制的使用同一個對象兩次或多次在不同的RealmList中繁涂,并且你可以使用這個去建立一對多或者多對多的關系盹靴。
你可以創(chuàng)建對象炸茧,然后使用RealmList.add()去把Email對象添加到Contact對象中:
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Contact contact = realm.createObject(Contact.class);
contact.name = "John Doe";
Email email1 = realm.createObject(Email.class);
email1.address = "john@example.com";
email1.active = true;
contact.emails.add(email1);
Email email2 = realm.createObject(Email.class);
email2.address = "jd@example.com";
email2.active = false;
contact.emails.add(email2);
}
});
把RealmList的字段設置為null會清空list,list會變?yōu)榭?長度為0)瑞妇,但對象并不會被刪除。
RealmList的getter方法永遠都不會返回為空梭冠,但返回的對象會一直是長度為0的list辕狰。
鏈式查詢
可以查詢鏈接或關系。
Consider the model below:
public class Person extends RealmObject {
private String id;
private String name;
private RealmList<Dog> dogs; // getters and setters
}
public class Dog extends RealmObject {
private String id;
private String name;
private String color; // getters and setters
}
每個Person的對象有不同dog的關系像如下表中:

我們查找某個Person通過鏈式查詢
// persons => [U1,U2]
RealmResults<Person> persons = realm.where(Person.class) .equalTo("dogs.color", "Brown") .findAll();
這個查詢會獲得所有Persons的dogs的color屬性為Brown的
或者通過persons的對象查詢中含有的Dog
persons.get(0).getDogs(); // => [A,B]
persons.get(1).getDogs(); // => [B,C,D]
這可以通過以下兩個查詢進一步檢查控漠。
// r1 => [U1,U2]
RealmResults<Person> r1 = realm.where(Person.class) .equalTo("dogs.name", "Fluffy") .findAll();
// r2 => [U1,U2]
RealmResults<Person> r2 = r1.where().equalTo("dogs.color", "Brown") .findAll();
Notice how the first query returned both Person
objects because the condition matched both persons. Each Person
in the query result contains a list of Dog
objects - all of their dog objects (even ones that do not fulfill the original query condition). Remember, we’re searching for people who have particular kinds of dogs (names and colors), not the actual dogs themselves. Therefore, the second query will be evaluated against the first Person
query result (r1
) and each of the Person
s dogs. The second query also matches both persons as well, but this time it’s because of the color of the dog.
Let’s dig a little deeper to help solidify this concept. Please review the following example:
// r1 => [U1,U2]
RealmResults<Person> r1 = realm.where(Person.class) .equalTo("dogs.name", "Fluffy") .equalTo("dogs.color", "Brown") .findAll();
// r2 => [U2]
RealmResults<Person> r2 = realm.where(Person.class) .equalTo("dogs.name", "Fluffy").findAll()
.where() .equalTo("dogs.color", "Brown").findAll()
.where() .equalTo("dogs.color", "Yellow").findAll();
第一句的查詢?yōu)槁叮檎宜蠵erson中dogs的“name”為“Fluffy”并且dogs的"color"為”Brown“的Person數據,第二句查詢?yōu)椴樵僤ogs的“name”為“Fluffy”盐捷,dogs的color為"Brown"和dogs的color為"Yellow"的Person集合
寫(Writes)
所有寫的操作(添加偶翅,修改,和移除對象)必須使用事務(transaction)碉渡。一個transaction可以被提交或者被取消聚谁,如果提交了,所有的改變都會更新到磁盤上滞诺。如果取消transaction形导,所有的改變都會取消。transaction的使用是線程安全的习霹。
// Obtain a Realm instance
Realm realm = Realm.getDefaultInstance()
realm.beginTransaction();//... add or update objects here ...
realm.commitTransaction();
當你開啟了事務后朵耕,你可以使用cancelTransaction來丟棄之前的更改
realm.beginTransaction();
User user = realm.createObject(User.class);// ...
realm.cancelTransaction();
請記住transactions是堵塞線程的,這會很容易導致ANR的錯誤淋叶,如果你在UI線程中和子線程中都創(chuàng)建transction了阎曹。為了避免ANR,請使用異步的transaction煞檩,當在UI線程中創(chuàng)建transanction時处嫌。
創(chuàng)建對象
創(chuàng)建對象請使用以下方法:
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();
事務堵塞(Transaction blocks)
除了 realm.beginTransaction(), realm.commitTransaction(), and realm.cancelTransaction(),你還可以使用realm.executeTransaction(),這個方法會自動調用begin/commit,然后發(fā)生錯誤時形娇,會調用cancel
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");
}
});
異步的事務(Asynchronous Transactions)
As transactions are blocked by other transactions it can be an advantage to do all writes on a background thread in order to avoid blocking the UI thread. By using an asynchronous transaction, Realm will run that transaction on a background thread and report back when the transaction is done.
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.
}
});
OnSuccess和OnError的回調是可選的锰霜,但是必須使用在創(chuàng)建了Looper的線程中
RealmAsyncTask transaction = 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");
} }, null);
異步事務由RealmAsyncTask的對象表示,在退出Activity/Fragment 時桐早,而transaction操作未完成癣缅,就可以使用這個對象進行取消事務操作,避免頁面崩潰
public void onStop () {
if (transaction != null && !transaction.isCancelled()) {
transaction.cancel();
}
}
查詢
Using the User class -
public class User extends RealmObject {
@PrimaryKey
private String name;
private int age;
@Ignore
private int sessionId; // Standard getters & setters generated by your IDE…
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSessionId() {
return sessionId;
}
public void setSessionId(int sessionId) {
this.sessionId = sessionId;
}
}
為了查找所有的users中name為“John”或“Peter”:
// Build the query looking at all users:
RealmQuery<User> query = realm.where(User.class);
// Add query conditions:
query.equalTo("name", "John");
query.or().equalTo("name", "Peter");
// Execute the query:
RealmResults<User> result1 = query.findAll();
// 或者鏈式調用
RealmResults<User> result2 = realm.where(User.class)
.equalTo("name", "John")
.or()
.equalTo("name", "Peter")
.findAll();
這會返回一個RealmResults的對象哄酝,這包含了姓名為John或Peter的user友存。
RealmResults繼承自AbstractList,跟普通的List有相同的特性,例如陶衅,你可以通過索引來查詢某個對象屡立,如果沒有匹配的,RealmResults不會為null搀军,但size()為0膨俐。
如果你想進行更改或者刪除對象在RealmResults中勇皇,你必須使用transaction。
between(), greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()
equalTo() & notEqualTo()
contains(), beginsWith()& endsWith()
isNull() & isNotNull()
isEmpty() & isNotEmpty()
不是所有的數據的類型都支持以上條件操作焚刺,請查詢相關RealmQueryAPI.
邏輯運算符
每個條件符的都是默認為一同使用敛摘,如果要使用or的邏輯,必須顯示調用or()操作符
Using the User class -
public class User extends RealmObject {
@PrimaryKey
private String name;
private int age;
@Ignore
private int sessionId; // Standard getters & setters generated by your IDE…
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSessionId() {
return sessionId;
}
public void setSessionId(int sessionId) {
this.sessionId = sessionId;
}
}
You can also group conditions with “parentheses” to specify order of evaluation: beginGroup()
is your “l(fā)eft parenthesis” and endGroup()
your “right parenthesis”:
RealmResults<User> r = realm.where(User.class)
.greaterThan("age", 10) //implicit AND
.beginGroup()
.equalTo("name", "Peter")
.or()
.contains("name", "Jo")
.endGroup()
.findAll();
Furthermore, it is possible to negate a condition with not(). The not() operator can be used with beginGroup()/endGroup() to negate sub-conditions only.
排序
Once you have done your query, you can sort the results like this:
RealmResults<User> result = realm.where(User.class).findAll();
result = result.sort("age"); // Sort ascending
result = result.sort("age", Sort.DESCENDING);
鏈式查詢
你可以高效地使用鏈式操作去查詢你的數據:
RealmResults<Person> teenagers = realm.where(Person.class).between("age", 13,20).findAll();
Person firstJohn = teenagers.where().equalTo("name", "John").findFirst();
You can also perform chained queries on child objects as well. Assume the above Person object has a list of Dog objects.
public class Dog extends RealmObject {
private int age; // getters & setters ...
}
public class Person extends RealmObject {
private int age;
private RealmList<Dog> dogs; // getters & setters ...
}
You can query for all people who are between the age of 13 and 20 who have at least one dog which is 1 year old:
RealmResults<Person> teensWithPups = realm.where(Person.class)
.between("age", 13, 20)
.equalTo("dogs.age", 1)
.findAll();
Note that query chains are built on RealmResults, not RealmQuery. If you add more conditions to an existing RealmQuery, then you are modifying the query, not the chains. Read more about link queries.
自動更新 結果(Auto-Updating Results)
RealmResults 是會自己進行更新的乳愉,這意味著不需要重新進行查詢操作兄淫,修改對象的操作會直接影響到之前查詢的結果
final RealmResults<Dog> puppies = realm.where(Dog.class).lessThan("age", 2).findAll();
puppies.size(); // => 0
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Dog dog = realm.createObject(Dog.class);
dog.setName("Fido");
dog.setAge(1);
}
});
puppies.addChangeListener(new RealmChangeListener() {
@Override
public void onChange(RealmResults<Dog> results) {
// results and puppies point are both up to date
results.size(); // => 1
puppies.size(); // => 1
}
});
這適用于所有RealmResults:所有對象、過濾和鏈接蔓姚。
這個特性不單止可以使Realm快和高效率捕虽,也可以使代碼更簡潔更有效。
你可以去 Realm notifications了解什么時候你的UI數據會進行更新坡脐。
聚合(Aggregation)[]
RealmResults 有以下方法:
RealmResults<User> results = realm.where(User.class).findAll();
long sum = results.sum("age").longValue();
long min = results.min("age").longValue();
long max= results.max("age").longValue();
double average = results.average("age");
long matches = results.size();
迭代(Iterations)
遍歷RealmResults里面的所有對象
你可以利用Iterable的特性:
RealmResults<User> results = realm.where(User.class).findAll();
for (User u : results) {
// ... do something with the object ...
}
或者使用常規(guī)的循環(huán)
RealmResults<User> results = realm.where(User.class).findAll();
for (int i = 0; i < results.size(); i++) {
User u = results.get(i); // ... do something with the object ...
}
RealmResults會自動地進行更新泄私,但是還會有很小的幾率在獲取對象后,不能匹配查詢或者刪除后的結果
final RealmResults<User> users = getUsers();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
users.get(0).deleteFromRealm(); // 非指向性刪除對象
}
});
for (User user : users) {
showUser(user); // 會導致crash
}
不要使用 deleteFromRealm()在RealmResults:
final RealmResults<User> users = getUsers();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
users.deleteFromRealm(0); // Delete and remove object directly
}
});
for (User user : users) {
showUser(user); // Deleted user will not be shown
}
刪除(Deletion)
你可以在進行查詢后進行刪除:
// obtain the results of a query
final RealmResults<Dog> results = realm.where(Dog.class).findAll();
// All changes to data must happen in a transaction
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
// remove single match
results.deleteFirstFromRealm();
results.deleteLastFromRealm();
// remove a single object
Dog dog = results.get(5);
dog.deleteFromRealm();
// Delete all matches
results.deleteAllFromRealm();
}
});
異步地查詢(Asynchronous Queries)
查詢可以使用子線程
大部分地Realm的同步查詢操作是非嘲ご耄快的挖滤,即使是在UI線程中崩溪。但是對于很復雜的查詢或者很大數據的查詢浅役,在子線程中進行查詢會更好
Example: finding users with name “John” or “Peter”
Create the query
RealmResults<User> result = realm.where(User.class)
.equalTo("name", "John")
.or()
.equalTo("name", "Peter")
.findAllAsync();
這個查詢會在子線程中進行,并且查詢完畢后伶唯,會立刻返回RealmResults的對象
如果你想響應查詢完成后的對象觉既,你可以注冊一個RealmChangeListener
注冊一個回調
private RealmChangeListener callback = new RealmChangeListener() {
@Override
public void onChange(RealmResults<User> results) {
// called once the query complete and on every update
}
};
public void onStart() {
RealmResults<User> result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
請記得要注銷任何一個listener在Acitvity或Fragment中,以避免內存泄漏
public void onStop () {
result.removeChangeListener(callback); // remove a particular listener
// or
result.removeChangeListeners(); // remove all registered listeners
}
檢測查詢是否完成
RealmResults<User> result = realm.where(User.class).findAllAsync();
if (result.isLoaded()) {
// Results are now available
}
同步地調用isLoaded()會一直返回true
使用異步檢測查詢(Force load an asynchronous query)
你可以直接等待查詢的結果乳幸。這會堵塞你當前的線程瞪讼,再次調用同步查詢即可
RealmResults<User> result = realm.where(User.class).findAllAsync();
result.load() // be careful, this will block the current thread until it returns
Realms
請在Application的子類中進行初始化:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
}
}
Realm的配置(Configuring a Realm)
最簡單地配置:
RealmConfiguration config = new RealmConfiguration.Builder().build();
一般我們會進行這樣的配置:
// The RealmConfiguration is created using the builder pattern.
// The Realm file will be located in Context.getFilesDir() with name "myrealm.realm"
RealmConfiguration config = new RealmConfiguration.Builder()
.name("myrealm.realm")
.encryptionKey(getKey())
.schemaVersion(42)
.modules(new MySchemaModule())
.migration(new MyMigration())
.build();
// Use the config
Realm realm = Realm.getInstance(config);
你也可以擁有不同的RealmConfigurations。以這種方式粹断,你可以獨立地控制每個Realm版本符欠,schema和位置
RealmConfiguration myConfig = new RealmConfiguration.Builder()
.name("myrealm.realm")
.schemaVersion(2)
.modules(new MyCustomSchema())
.build();
RealmConfiguration otherConfig = new RealmConfiguration.Builder()
.name("otherrealm.realm")
.schemaVersion(5)
.modules(new MyOtherSchema())
.build();
Realm myRealm = Realm.getInstance(myConfig);
Realm otherRealm = Realm.getInstance(otherConfig);
通過調用Realm.getPath()可以獲得Realm的絕對路徑
默認地配置(The Default RealmConfiguration)
RealmConfiguration會被設置為默認的configuration,設置一個默認的configuration在你自己的Application中
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// The Realm file will be located in Context.getFilesDir() with name "default.realm"
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().build();
Realm.setDefaultConfiguration(config);
}
}
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Realm realm = Realm.getDefaultInstance();
try {
// ... Do something ...
}finally {
realm.close();
}
}
}
定義一個不需要持久化的Realm:
RealmConfiguration myConfig = new RealmConfiguration.Builder().name("myrealm.realm")
.inMemory()
.build();
這會創(chuàng)建一個保存在內存中而不保存在磁盤中的Realm對象,In-memory Realms會使用磁盤內存如果內存過低時瓶埋,但Realm關閉時希柿,會刪除所有數據
數據庫遷移(Migrations)
如果數據庫要進行升級,
This can be avoided by setting the schema version and migration code in RealmConfiguration
.
RealmConfiguration config = new RealmConfiguration.Builder()
.schemaVersion(2) // Must be bumped when the schema changes
.migration(new MyMigration()) // Migration to run instead of throwing an exception
.build()
使用自定義的Migration,可以方便進行舊版本數據的操作养筒,如下:
// Example migration adding a new class
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++;
}
}
}
如果是測試階段,使用以下的配置進行測試:
RealmConfiguration config = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build();
author lxw
date 2017.2.15