Tag:對(duì)于自己認(rèn)定的事情,要堅(jiān)持乔煞。
Realm 是一個(gè)移動(dòng)數(shù)據(jù)庫(kù),可運(yùn)行于手機(jī)柒室、平板和可穿戴設(shè)備之上渡贾。可以讓你的應(yīng)用更快速雄右,帶來難以想象的體驗(yàn)空骚。其目標(biāo)是為了代替 CoreData 和 SQLite 數(shù)據(jù)庫(kù)。
易用
Ream 不是在SQLite基礎(chǔ)上的ORM擂仍,它有自己的數(shù)據(jù)查詢引擎囤屹。并且十分容易使用。
跨平臺(tái)
Realm 支持 iOS & OS X (Objective?C & Swift) & Android逢渔。我們可以在這些平臺(tái)上共享Realm數(shù)據(jù)庫(kù)文件肋坚,并且上層邏輯可以不用任何改動(dòng)的情況下實(shí)現(xiàn)移植。
高級(jí)
Ream支持加密肃廓,格式化查詢智厌,易于移植,支持JSON盲赊,流式api铣鹏,數(shù)據(jù)變更通知等高級(jí)特性
Realm的使用條件
- 目前不支持Android以外的Java
- Android Studio >= 1.5.1
- 較新的Android SDK版本
- JDK version >=7.
- 支持API 9(Android 2.3)以及之后的版本
一.加入依賴關(guān)系
1、在project的build中加入依賴
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:2.2.1"
}
}
2哀蘑、 在module中加入
apply plugin: 'realm-android
二.創(chuàng)建和初始化
1诚卸、使用RealmConfiguration配置Realm
創(chuàng)建數(shù)據(jù)庫(kù)時(shí)首先需要調(diào)用Realm.init()方法,否則系統(tǒng)報(bào)錯(cuò):Java.lang.IllegalStateException: Call Realm.init(Context)
before creating a RealmConfiguration
數(shù)據(jù)庫(kù)初始化主要工作是什么數(shù)據(jù)庫(kù)的name(設(shè)置數(shù)據(jù)庫(kù)的文件名稱)绘迁、schemaVersion(設(shè)置當(dāng)前數(shù)據(jù)庫(kù)版本號(hào)合溺,當(dāng)前版本號(hào)不能小于歷史版本號(hào))、migration(數(shù)據(jù)庫(kù)版本遷移)缀台、 deleteRealmIfMigrationNeeded(版本沖突時(shí)刪除原始數(shù)據(jù)庫(kù))棠赛、inMemory(在內(nèi)存中持久化,關(guān)閉后自動(dòng)刪除)、build(創(chuàng)建數(shù)據(jù)庫(kù))恭朗。
public static Realm getRealm(Context context)
{
byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
Realm.init(context);
Migration migration = new Migration();
RealmConfiguration config = new RealmConfiguration.Builder()
.name("realmdb.realm") //文件名
.schemaVersion(0) //版本號(hào)
.migration(migration)//數(shù)據(jù)庫(kù)版本遷移(數(shù)據(jù)庫(kù)升級(jí)屏镊,當(dāng)數(shù)據(jù)庫(kù)中某個(gè)表添加字段或者刪除字段)
.deleteRealmIfMigrationNeeded()//聲明版本沖突時(shí)自動(dòng)刪除原數(shù)據(jù)庫(kù)(當(dāng)調(diào)用了該方法時(shí),上面的方法將失效)痰腮。
.build();//創(chuàng)建
return Realm.getInstance(config);
}
2而芥、 創(chuàng)建model
創(chuàng)建一個(gè)類名為User的model,首先該類必須繼承自RealmObject膀值,只有這才用使用Realm來操作model生成相應(yīng)的表棍丐。
在Realm支持的類型有:boolean, byte, short,int,long,float, double,String, Date,byte[], RealmObject, RealmList<? extends RealmObject>還支持Boolean, Byte, Short, Integer, Long, Float 和 Double沧踏。但是:整數(shù)類型 short歌逢、int 和 long 都被映射到 Realm內(nèi)的相同類型(實(shí)際上為 long )。
@PrimaryKey——表示該字段是主鍵
PrimaryKey就是主鍵翘狱。使用@PrimaryKey來標(biāo)注秘案,字段類型必須是字符串(String)或整數(shù)(byte,short潦匈,int或long)以及它們的包裝類型(Byte,Short, Integer, 或 Long)阱高。一個(gè)model中不可以存在多個(gè)主鍵,使用字符串字段作為主鍵意味著字段被索引(注釋@PrimaryKey隱式地設(shè)置注釋@Index)茬缩。
@Required——表示該字段非空
在某些情況下赤惊,某些屬性是不能為null的。使用@Required可用于用于強(qiáng)行要求其屬性不能為空凰锡,只能用于Boolean, Byte, Short, Integer, Long, Float, Double, String, byte[] 和 Date未舟。在其它類型屬性上使用
@Required修飾會(huì)導(dǎo)致編譯失敗。
note:基本數(shù)據(jù)類型不需要使用注解 @Required掂为,因?yàn)樗麄儽旧砭筒豢蔀榭铡?/p>
@Ignore——表示忽略該字段
如果想忽略某個(gè)字段裕膀,則可以使用@Ignore修飾該字段,被秀@ignore修飾的字段在存儲(chǔ)數(shù)據(jù)時(shí)會(huì)忽略該字段菩掏。
@Index——添加搜索索引
使用@index可以為字段添加搜索索引魂角,使用索引以后使得插入的速度變慢,數(shù)據(jù)量也變得更大智绸。但是在查詢速度將變得更快,所以建議只在優(yōu)化讀取性能的特定情況時(shí)添加索引访忿。
支持索引:String瞧栗,byte,short海铆,int迹恐,long,boolean和Date字段卧斟。
public class User extends RealmObject
{
@PrimaryKey
private int id;
private int age;
@Required
private String name;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
private RealmList<Dog> dogs;
public RealmList<Dog> getDogs()
{
return dogs;
}
public void setDogs(RealmList<Dog> dogs)
{
this.dogs = dogs;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
4殴边、增
寫入操作需要在事務(wù)中進(jìn)行憎茂,
*使用executeTransaction方法來開啟事務(wù)。
當(dāng)model沒有primaryKey時(shí)锤岸,可以使用下面的方法
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User user = realm.createObject(User.class);
user.setName("Gavin");
user.setAge(23);
user.setId(1);
}});
當(dāng)model有primaryKey時(shí)竖幔,則可以使用下面的方法,將對(duì)@primaryKey修飾的字段直接在創(chuàng)建對(duì)象是賦值(createObject(User.class,1))
mRealm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
User user = realm.createObject(User.class是偷,1);
user.setName("Gavin");
user.setAge(23);
}});
使用copyToRealmOrUpdate或copyToRealm方法插入數(shù)據(jù)
當(dāng)model中含有primaryKey時(shí)使用copyToRealmOrUpdate插入數(shù)據(jù)拳氢,在當(dāng)前插入主鍵的值存在時(shí)則修改對(duì)應(yīng)主鍵值相關(guān)的數(shù)據(jù)信息,否則插入數(shù)據(jù)蛋铆。
當(dāng)model中不含有主鍵時(shí)馋评,則使用copyToRealm。若在不含有主鍵的model中使用copyToRealmOrUpdate將拋異常:
java.lang.IllegalArgumentException: A RealmObject with no @PrimaryKey cannot be updated:XXXXX
final User user = new User();
user.setName("李德華");
user.setUserId("admin");
user.setAge(25);
user.setId(1);
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
realm.copyToRealmOrUpdate(user);
}
});
當(dāng)在model(User)中包辦另外一個(gè)model例如在User中包含一個(gè)Dog模型刺啦,也可以包含一個(gè)Dog的集合
還記得在之前的User數(shù)據(jù)模型中含有這么一塊代碼嗎留特?這個(gè)申明表示一個(gè)User中可以包含(養(yǎng))多條狗(Dog)
在Realm中List類型表示為RealmList。
private RealmList<Dog> dogs;
public RealmList<Dog> getDogs()
{
return dogs;
}
public void setDogs(RealmList<Dog> dogs)
{
this.dogs = dogs;
}
向數(shù)據(jù)模型(User)插入另外一個(gè)數(shù)據(jù)模型(Dog)時(shí)玛瘸,可以才用如下方式(當(dāng)User含有主鍵時(shí)采用):
private void insertOrUpdateDataWithPrimaryKey()
{
final User user = new User();
user.setName("李德華");
user.setUserId("admin");
user.setAge(25);
user.setId(1);
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
Dog dog1 = new Dog();
dog1.setId(1);
dog1.setAge(5);
dog1.setName("藏獒");
dogs = new RealmList<Dog>();
dogs.add(dog1);
user.setDogs(dogs);
realm.copyToRealmOrUpdate(user);
}
});
}
當(dāng)user沒有主鍵時(shí)使用如下方式:
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm) {
User user = realm.createObject(User.class);
user.setName("Gain");
user.setAge(23);
Dog dog1 = realm.createObject(Dog.class);
dog1.setAge(1);
dog1.setName("二哈");
user.getDogs().add(dog1);
Dog dog2 = realm.createObject(Dog.class);
dog2.setAge(2);
dog2.setName("阿拉撕家");
user.getDogs().add(dog2);
}
});
使用異步方式進(jìn)行數(shù)據(jù)插入蜕青,具體的方式如下:
使用異步插入,可以檢測(cè)數(shù)據(jù)是否插入成功捧韵,成功后可以使用new Realm.Transaction.OnSuccess()進(jìn)行監(jiān)測(cè)市咆,失敗可以使用new Realm.Transaction.OnError()監(jiān)測(cè)。
/**
* 異步執(zhí)行
* 向有主鍵的數(shù)據(jù)表中insert或update數(shù)據(jù)
* 數(shù)據(jù)表中有當(dāng)前主鍵時(shí)則執(zhí)行update
* 否者執(zhí)行insert
*/
private void insertOrUpdateDataWithPrimaryKeyAsync()
{
final User user = new User();
user.setName("李德華");
user.setUserId("admin");
user.setAge(25);
user.setId(1);
task = realm.executeTransactionAsync(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
Dog dog1 = new Dog();
dog1.setId(1);
dog1.setAge(5);
dog1.setName("藏獒");
dogs = new RealmList<Dog>();
dogs.add(dog1);
user.setDogs(dogs);
realm.copyToRealmOrUpdate(user);
}
}, new Realm.Transaction.OnSuccess()
{
@Override
public void onSuccess()
{
Logger.d("Success");
}
}, new Realm.Transaction.OnError()
{
@Override
public void onError(Throwable error)
{
Logger.d("Error");
}
});
}
注意:如果當(dāng)Acitivity或Fragment被銷毀時(shí)再来,在OnSuccess或OnError中執(zhí)行UI操作蒙兰,將導(dǎo)致程序奔潰 。用RealmAsyncTask .cancel();可以取消事務(wù)芒篷,在onStop中調(diào)用搜变,避免crash
@Override
protected void onStop()
{
super.onStop();
if (task != null && task.isCancelled())
{
task.cancel();
}
}
將Json數(shù)據(jù)直接插入數(shù)據(jù)庫(kù)
Realm有一個(gè)強(qiáng)大的功能就是將Json數(shù)據(jù)直接插入到相應(yīng)的數(shù)據(jù)庫(kù),具體的代碼入下:
/**
* 將Json數(shù)據(jù)添加到數(shù)據(jù)表中
*/
private void insertDataFromJson()
{
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
realm.createOrUpdateObjectFromJson(User.class, "{ id: 2, age: 50, name:\"sealong\",userId:\"admin\",
dogs:[{id:5,name:\"龍騎士\",age:3},{id:6,name:\"豬騎士\",age:4},{id:7,name:\"馬騎士\",age:5}]}");
}
});
}
Realm 解析 JSON 時(shí)遵循如下規(guī)則:
1.使用包含空值(null)的 JSON 創(chuàng)建對(duì)象:
2.對(duì)于非必須(可為空值的屬性)针炉,設(shè)置其值為 null挠他;
3.對(duì)于必須(不可為空值的屬性),拋出異常篡帕;
4.使用包含空值(null)的 JSON 更新對(duì)象:
5.對(duì)于非必須(可為空值的屬性)殖侵,設(shè)置其值為 null;
6.對(duì)于必須(不可為空值的屬性)镰烧,拋出異常钱雷;
7.使用不包含對(duì)應(yīng)屬性的 JSON: * 該屬性保持不變
5.刪
Realm的刪除凉唐,包含兩個(gè)步驟,首先查找到相應(yīng)的數(shù)據(jù)集合,在在集合中刪除相應(yīng)的數(shù)據(jù)烁挟,代碼如下:
private void deleteData()
{ //先查找到數(shù)據(jù)
final RealmResults<User> userList = realm.where(User.class).findAll();
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
userList.get(4).deleteFromRealm();//刪除指定位置(第4條記錄)的記錄
userList.deleteFromRealm(4);//刪除指定位置(第4條記錄)的記錄
userList.deleteFirstFromRealm(); //刪除user表的第一條數(shù)據(jù)
userList.deleteLastFromRealm();//刪除user表的最后一條數(shù)據(jù)
userList.deleteAllFromRealm();//刪除user表的全部數(shù)據(jù)
}
});
}
6.改
改是通過先查找到相應(yīng)的數(shù)據(jù),然后再設(shè)置需要修改的相應(yīng)的信息。
例如修改User表中name=sealong 并且Id=2的所有對(duì)象,并將其UserId設(shè)置為user的代碼如下艾凯。
private void dataUpdate()
{
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realms)
{
//先查找后得到User對(duì)象
RealmResults<User> users = realm.where(User.class).equalTo("name", "sealong").equalTo("id", 2).findAll();
for (User user : users)
{
user.setUserId("user");
}
}
});
}
7.查
查找常用的函數(shù)有:
findAll ---- 查詢滿足條件的所有記錄
findAllAsync----異步查詢(當(dāng)數(shù)據(jù)量較大,可能會(huì)引起ANR的時(shí)候懂傀,就可以使用findAllAsync)
findFirst ---- 查詢第一條數(shù)據(jù)
equalTo ---- 根據(jù)條件查詢(多次使用該函數(shù)可以實(shí)現(xiàn)多條件查詢)
sum ---- 對(duì)指定字段求和趾诗。
average ---- 對(duì)指定字段求平均值。
min ---- 對(duì)指定字段求最小值鸿竖。
max ---- 對(duì)指定字段求最大值沧竟。count : 求結(jié)果集的記錄數(shù)量。
findAll ---- 返回結(jié)果集所有字段缚忧,返回值為
RealmResults隊(duì)列
findAllSorted ---- 排序返回結(jié)果集所有字段悟泵,返回值為RealmResults隊(duì)列
between ---- 指定字段的值在某區(qū)間內(nèi)
greaterThan()|lessThan()----指定字段的值大于(小于)給定的值
greaterThanOrEqualTo() & lessThanOrEqualTo()----指定字段的值大于等于(小于等于)給定的值
equalTo() & notEqualTo() ---- 指定字段的值(不)等于
contains() ----指定字段的值包含某些字符(指定字段為String)
beginsWith() & endsWith() ----指定字段的值以給定的值開始(結(jié)束)
isNull() & isNotNull() ----指定字段的值(不)為null
isEmpty() & isNotEmpty() ----指定字段的值(不)為空
private void dataSelectUser()
{
RealmResults<User> users = realm.where(User.class).findAllSorted("id", Sort.DESCENDING);//按照id倒序排序
long size = users.size();//返回?cái)?shù)據(jù)的條數(shù)
double average = users.average("age");//返回查詢結(jié)果的中age的平均值
long sum = users.sum("age").longValue();//返回查詢結(jié)果中age的總數(shù)
long min = users.min("age").longValue();//返回查詢結(jié)果中age的最小值
long max = users.max("age").longValue();//返回查詢結(jié)果中age的最大值
}
8.數(shù)據(jù)庫(kù)升級(jí)
當(dāng)某個(gè)數(shù)據(jù)表需要加某些字段或者添加某些屬性時(shí),而且不刪除之前的原始數(shù)據(jù)的情況下闪水,需要對(duì)原始數(shù)據(jù)進(jìn)行升級(jí)
例如需要對(duì)表刪除字段age糕非,并且需要添加一個(gè)String類型的userId 并且設(shè)置將之前表中的userId的值設(shè)置為1,同時(shí)版本號(hào)需要更新
public class Migration implements RealmMigration
{
/**
* 升級(jí)數(shù)據(jù)庫(kù)
*/
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion)
{
RealmSchema schema = realm.getSchema();
if (oldVersion != newVersion)
{
RealmObjectSchema personSchema = schema.get("User");
//新增@Required的id
personSchema.addField("userId", String.class, FieldAttribute.REQUIRED)
.transform(new RealmObjectSchema.Function()
{
@Override
public void apply(DynamicRealmObject obj)
{
obj.set("userId", "1");//為id設(shè)置值
}
}).removeField("age");
oldVersion++;
}
}
}
轉(zhuǎn)載自: Realm在android的應(yīng)用