文章目錄
Realm(Java)數據庫使用文檔(目錄)
本節介紹如何將Realm與其他常用的Android庫集成。
14.1 GSON
GSON是Google創建的用於反序列化和序列化JSON的庫。GSON應該與Realm開箱即用。
// Using the User class
public class User extends RealmObject {
private String name;
private String email;
// getters and setters left out ...
}
Gson gson = new GsonBuilder().create();
String json = "{ name : 'John', email : '[email protected]' }";
User user = gson.fromJson(json, User.class);
您還可以在我們的GridViewExample中看到GSON如何與Realm一起工作的示例。
14.2 序列化Serialization
爲了與諸如Retrofit之類的庫完全兼容,您通常會希望能夠同時反序列化和序列化對象。將Realm對象序列化爲JSON不適用於GSON的默認行爲,因爲GSON將使用字段值而不是getter和setter。
要使GSON序列化與Realm一起使用,您需要爲每個可以序列化的對象編寫一個自定義JsonSerializer(連接已失效),並將其註冊爲TypeAdapter(連接已失效)。
本要點說明了如何實現。
14.3 原始清單Primitive lists
儘管Realm在本地支持將JSON中的數組導入到原語列表,但是缺少對原語列表的查詢支持仍然可能是一個問題。您可能希望將基本類型的JSON數組作爲RealmObject的列表導入。如果無法更改JSON API,則可以編寫GSON的自定義TypeAdapter(連接已失效),該適配器自動在JSON的原始類型和Realm使用的包裝對象之間進行映射。
在本要點中,是一個爲Integer使用包裝對象的示例,但是該模板可以用於具有Realm支持的數據類型的所有基本數組。
14.4 故障排除Troubleshooting
Realm對象可以包含內部包含循環引用的字段。發生這種情況時,GSON可能會拋出StackOverflowError。我們已經看到,當Realm對象具有Drawable字段時,會發生這種情況:
public class Person extends RealmObject {
@Ignore
Drawable avatar;
// other fields, etc
}
上面的Person類包含一個應用了@Ignore批註的Android Drawable。在GSON序列化期間,正在檢查Drawable並導致StackOverflowError(GitHub問題)。爲了減輕這種情況,請將以下代碼添加到shouldSkipField方法中。
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class) || f.getDeclaringClass().equals(Drawable.class);
}
請注意Drawable.class評估。這告訴GSON在序列化期間跳過此字段。添加此選項將緩解StackOverflowError。
14.5 Jackson 數據綁定
Jackson Databind是用於將JSON數據綁定到Java類的庫。
Jackson使用反射來執行數據綁定。這與Realm對RxJava的支持相沖突,因爲RxJava可能無法用於類加載器。這可能會導致如下所示的異常:
java.lang.NoClassDefFoundError: rx.Observable
at libcore.reflect.InternalNames.getClass(InternalNames.java:55)
...
可以通過將RxJava添加到您的項目或創建兩個類似於以下內容的空虛擬文件來解決此問題。
// File 1
package io.reactivex;
public class Flowable {
}
// File 2
package io.reactivex;
public class Observable {
}
// File 3
package io.reactivex;
enum BackpressureStrategy {
LATEST;
}
此問題也已報告給此處的Jackson項目。
14.6 Kotlin
Realm與Kotlin編程語言完全兼容。請參閱Kotlin指南。
14.7 Parceler
Parceler是一個庫,可自動生成使對象遵守Parcelable接口所需的樣板。由於Realm使用代理類,因此Parceler需要以下設置才能與Realm的模型類一起使用。
Realm中的代理類使用模型類的全限定名稱加上RealmProxy後綴,因此例如io.realm.model.Person
成爲io_realm_model_PersonRealmProxy.class
// 所有擴展RealmObject的類都將具有一個由註釋處理器創建的匹配的RealmProxy類。必須使包裹程序知道此類。請注意,只有在項目至少編譯一次之後,該類纔可用。
@Parcel(implementations = { some_package_PersonRealmProxy.class },
value = Parcel.Serialization.BEAN,
analyze = { Person.class })
public class Person extends RealmObject {
// ...
}
如果您使用Gradle獲取Parceler,請確保存在以下幾行(有關更多詳細信息,請參見此處):
compile "org.parceler:parceler-api:1.0.3"
apt "org.parceler:parceler:1.0.3"
使用Parceler時要注意一些重要限制:
- 如果您的模型包含RealmList,則需要註冊一個特殊的適配器。
- 打包對象後,它就會與Realm分離,此時的行爲就像是包含數據快照的非託管對象。對該對象的進一步更改將不會保留在Realm中。
14.8 Retrofit
Retrofit是Square提供的一個庫,可以輕鬆以類型安全的方式使用REST API。
Realm可以同時使用Retrofit 1. *和2. *,但是請注意Retrofit不會自動將對象添加到Realm,而是必須使用realm.copyToRealm()或realm.copyToRealmOrUpdate()方法手動添加它們。
GitHubService service = restAdapter.create(GitHubService.class);
List<Repo> repos = service.listRepos("octocat");
// 將元素從Retrofit複製到Realm以保留它們。
realm.beginTransaction();
List<Repo> realmRepos = realm.copyToRealmOrUpdate(repos);
realm.commitTransaction();
14.9 Robolectric
Robolectric是一個庫,可讓您直接在JVM中而不是在電話或仿真器中運行JUnit測試。當前,Robolectrics不支持與Realm捆綁在一起的本機庫。這意味着目前尚無法使用Robolectric測試Realm。
您可以在此處關注功能請求:https://github.com/robolectric/robolectric/issues/1389
14.10 RxJava
RxJava是Netflix的一個Reactive Extensions庫,它擴展了Observer模式。這樣就可以觀察到數據變化的可組合序列。
Realm對RxJava 2 Flowable和Observable具有一流的支持
- Realm
- RealmResults
- RealmList
- RealmObject
- DynamicRealm
- DynamicRealmObject
- RealmResults changesets
- RealmList changesets
- RealmObject changesets
- DynamicRealmObject changesets
//結合Realm、Retrofit和RxJava(爲簡潔起見,使用Retrolambda語法)
//加載所有人並將其與來自GitHub的最新統計信息合併(如果有的話)
Realm realm = Realm.getDefaultInstance();
GitHubService api = retrofit.create(GitHubService.class);
realm.where(Person.class).isNotNull("username").findAllAsync().asFlowable()
.filter(persons.isLoaded)
.flatMap(persons -> Observable.from(persons))
.flatMap(person -> api.user(person.getGithubUserName())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> showUser(user));
異步查詢是非阻塞的-上面的代碼將立即返回RealmResults實例。如果要確保僅對加載的列表進行操作,請通過過濾器運算符過濾Flowable,然後通過調用[RealmResults.isLoaded](api/io/realm/RealmResults.html#isLoaded–)方法檢查列表。通過檢查“RealmResults”是否已加載,可以確定查詢是否已完成。
Realm 7.0版中的新功能:所有Realm Observable和Flowables都返回凍結的對象。這意味着這些對象是不可變的,但是可以從任何線程或調度程序讀取和查詢,而不必擔心會遇到IllegalStateException
:來自錯誤線程的realm訪問。
有關更多示例,請參見RxJava示例項目。
RxJava是一個可選的依賴項,這意味着Realm不會自動包含它。這樣的好處是您可以選擇使用哪個版本的RxJava,並且避免在不使用RxJava的項目中方法計數過大。必須將RxJava手動添加到build.gradle
文件中。
dependencies {
compile 'io.reactivex:rxjava:2.1.4'
}
通過創建自定義RxObservableFactory,可以配置Realm如何創建流。使用RealmConfiguration進行配置。
RealmConfiguration config = new RealmConfiguration.Builder()
.rxFactory(new MyRxFactory())
.build()
如果未定義RxObservableFactory,則Realm默認爲RealmObservableFactory,這是Realm提供的支持RxJava <= 2. *的類。 從Realm版本7.0.0開始,可以將此類配置爲返回活動或凍結對象。 默認值爲凍結對象。
// 禁用可觀察對象的凍結對象
RealmConfiguration config = new RealmConfiguration.Builder()
.rxFactory(new RealmObservableFactory(false))
.build()
如果您使用的是RxJava 1,則可以使用David Karnok的該庫在RxJava 2和RxJava 1類型之間進行轉換。