Realm Java 0.87 — with RxJava support!
We just released a new version of Realm Java to this website and to Maven. This release includes first-class API support for RxJava.
RxJava
RxJava is a Reactive Extensions library from Netflix that extends the Observer pattern. It makes it possible to work with changes to Realm data using composable sequences of operators. All Realm classes except RealmQuery
and RealmList
can now be exposed as an Observable
(https://github.com/ReactiveX/RxJava/wiki/Observable).
Realm Observables are built on top of our standard RealmChangeListener
, so any Observable will emit objects at the same rate as the change listener would have been notified.
Realm realm = Realm.getDefaultInstance();
RealmResults<Person> persons = realm.where(Person.class).findAll();
Person person = persons.first();
Observable<Realm> realmObservable = realm.asObservable();
Observable<RealmResults<Person>> resultsObservable = persons.asObservable();
Observable<Person> objectObservable = person.asObservable();
This also works with Realm’s Async API.
realm.where(Person.class).equalTo("name", "John").findAllAsync().asObservable()
.filter(new Func1<RealmResults<Person>, Boolean>() {
@Override
public Boolean call(RealmResults<Person> persons) {
// Ignore unloaded results
return persons.isLoaded();
}
})
.subscribe(new Action1<RealmResults<Person>>() {
@Override
public void call(RealmResults<Person> persons) {
// Show persons...
}
});
See the RxJava example project for more examples.
Configuration
Although RxJava is now a first-class citizen in our API, it is still an opt-in dependency. This means you have to provide RxJava yourself in build.gradle
. This has the benefits of letting you decide which version of RxJava you want to use and preventing method count bloat for projects that don’t use RxJava.
dependencies {
compile 'io.realm:realm-android:0.87.0'
compile 'io.reactivex:rxjava:1.1.0'
}
We also added a new interface called RxObservableFactory
for people that want to customize how the Observables are created. A custom factory can be configured using RealmConfiguration
, but Realm comes with a RealmObservableFactory
class which is used as the default factory. It supports RxJava <= 1.1.*.
RealmConfiguration config = new RealmConfiguration.Builder(context)
.rxFactory(new MyFactory())
.build()
Work-in-progress
While we are shipping initial support for RxJava now, we still lack Observable support for RealmQuery
and RealmList
. These will be added in a future update.
It is also important to remember that RealmObject
and RealmResults
are still thread confined. This means that is not possible to load Realm objects on one thread and use them on another.
// Default pattern for loading data on a background thread
Observable.defer(new Func0<Observable<RealmResults<Person>>>() {
@Override
public Observable<RealmResults<Person>> call() {
return realm.where(Person.class).findAll().asObservable();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<RealmResults<Person>>() {
@Override
public void call(RealmResults<Person> persons) {
// Accessing persons here would crash.
}
});
// Instead, use Realms Async API for the same effect
realm.where(Person.class).findAllAsync().asObservable()
.subscribe(new Action1<RealmResults<Person>>() {
@Override
public void call(RealmResults<Person> persons) {
// Show data in the UI
}
});
RealmObject
s and RealmResults
are also live objects, which means that they are continuously updated with the latest data from Realm. This is great for consistency, but doesn’t work well with RxJava’s model that favor immutable thread‑safe objects. Therefore, we have added Realm.copyFromRealm()
which makes it possible to copy Realm data into normal Java objects, effectively detaching them from Realm. This has a cost in terms of both speed and memory usage but can make it easier to work with operators such as buffer()
.
// Get different versions of a person
realm.where(Person.class).findFirst().<Person>asObservable()
.map(new Func1<Person, Person>() {
@Override
public Person call(Person person) {
// Convert live object to a static copy
return realm.copyFromRealm(person);
}
})
.buffer(2)
.subscribe(new Action1<List<Person>>() {
@Override
public void call(List<Person> persons) {
// Without `map` and `copyFromRealm`, v1 and v2 would be the same
Person v1 = persons.get(0);
Person v2 = persons.get(1);
}
});
Solutions for avoiding this work-around will be added in a future update.
See the full changelog for all the details.
Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, and Twitter.