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
      }
  });

RealmObjects 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.