3

I'm trying to figure out a way to save my Parsed objects from retro into realm through rxjava observable.

Right now I have an API call:

fetchCatalogData().subscribeOn(Schedulers.io())
                  .subscribe(data ->
                       saveToRealm();
                  )

This doesn't work because either I'm using realm on different treads or that scheduler.io doesn't have a looper. I'm not sure what's the best way to work with retrofit, realm and rxjava. I want to be able to save all my data when it arrives from retrofit and then access it afterwards.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
jhysum
  • 41
  • 1
  • 2
  • 1
    I found another post that had an answer that worked. https://stackoverflow.com/questions/35897737/how-to-combine-retrofit-2-with-realm-and-rxjava – jhysum Mar 14 '16 at 02:25

3 Answers3

3

You may leverage a very good library that combines all.

https://github.com/FabianTerhorst/ApiClient

"An easy to use api client that combines the power of Retrofit, Realm, Gson, Rxjava and Retrolambda in a easy to use library for Java and Android"

Rakesh Waghela
  • 2,227
  • 2
  • 26
  • 46
3

It's actually rather simple, all you need to do is have two different streams - one for the download, and one for displaying the data.

I'm assuming fetchCatalogData() returns the data via Retrofit, therefore unmanaged objects.

fetchCatalogData()
.subscribeOn(Schedulers.io())
.subscribe(data ->
     saveToRealm(data);
)

In this case this works just fine, as long as saveToRealm() opens a thread-specific Realm-instance:

private void saveToRealm(CatalogData data) {
    try(Realm r = Realm.getDefaultInstance()) {
        r.executeTransaction((realm) -> {
            realm.insertOrUpdate(data);
        });
    }
}

This would allow you to create a Realm (which gets auto-closed) on the background thread, and persist to the Realm.


For the UI thread, you would create a query for CatalogData, and via RxJava-support of Realm you get a RealmChangeListener appended to the result set, and receive a "hot Observable" which gives you the results whenever the underlying table changes.

Subscription showCatalog = realm.where(CatalogData.class)
                                .findAllAsync()
                                .filter(RealmResults::isLoaded)
                                .filter(RealmResults::isValid) 
                                .subscribe((results) -> {
                                    adapter.updateData(results);
                                });
Graham
  • 7,431
  • 18
  • 59
  • 84
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
1

Realm works with both Retrofit 1.* and 2.* out of the box, but note that Retrofit does not automatically add objects to Realm, instead you must manually add them using the realm.copyToRealm() or realm.copyToRealmOrUpdate() methods.

GitHubService service = restAdapter.create(GitHubService.class);
List<Repo> repos = service.listRepos("octocat");

// Copy elements from Retrofit to Realm to persist them.
realm.beginTransaction();
List<Repo> realmRepos = realm.copyToRealmOrUpdate(repos);
realm.commitTransaction();

Also Realm has first-class support for RxJava, which means that the following Realm classes can be exposed as an Observable: Realm, RealmResults, RealmObject, DynamicRealm and DynamicRealmObject.

// Combining Realm, Retrofit and RxJava (Using Retrolambda syntax for brevity)
// Load all persons and merge them with their latest stats from GitHub (if they have any)
Realm realm = Realm.getDefaultInstance();
GitHubService api = retrofit.create(GitHubService.class);
realm.where(Person.class).isNotNull("username").findAllAsync().asObservable()
.filter(persons.isLoaded)
.flatMap(persons -> Observable.from(persons))
.flatMap(person -> api.user(person.getGithubUserName())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> showUser(user));

This this official Realm docs.

Volodymyr
  • 6,393
  • 4
  • 53
  • 84