Search code examples
androidrealmrx-java2

Realm instance has already been closed - with RxJava2


I used Realm in conjunction with RxJava it this way:

public Flowable<List<EventEntity>> getAll() {
  try (final Realm realm = Realm.getInstance(mRealmConfiguration)) {
    RealmQuery<RealmEvent> query = realm.where(RealmEvent.class);
    Flowable<RealmResults<RealmEvent>> result;
    if (realm.isAutoRefresh()) {
       result = query
       .findAllAsync()
       .asFlowable()
       .filter(RealmResults::isLoaded);
    } else {
      result = Flowable.just(query.findAll());
    }
    return result
      .unsubscribeOn(AndroidSchedulers.mainThread());
  }
}

I use this chain on multiple places in app. For example:

return Observable.merge(
      mEventRepository.getAll()
        .toObservable(),
      subjectNotificationChange
        .flatMapMaybe(notification ->
          mEventRepository.getAll()
            .firstElement()
        )
    )

Problem is that I obtain exception: java.lang.IllegalStateException: This Realm instance has already been closed, making it unusable.

I looked at implementation method from of RealmObservableFactory and each call of subscribe method should create new instance of Realm. Entire situation looks as problem with references counting.

Do you know where is problem?


Solution

  • Java's try-with-resource closes the resource as soon as you leave the code block, but RxJava being lazy and all, only begins working when you actually subscribe, which happens after your code exits the getAll() function.

    Edit: since you build a special Realm instance each time, passing configuration to it, the instance is not shared and therefore definitively closed each time.

    Instead, initialize your Realm earlier using Realm.setDefaultConfiguration(config). Then, use Realm.getDefaultInstance() in your function so you access the default shared instance instead of creating a new one each time.

    Edit2: the easiest solution is to keep a reference to the Realm instance:

    class MyRepository {
    
        private final Realm realm;
    
        public MyRepository(Realm realm) {
            this.realm = realm;
        }
    
        public Flowable<List<EventEntity>> getAll() {
            RealmQuery<RealmEvent> query = realm.where(RealmEvent.class);
            // ...
        }
    
    }
    
    Realm realm = Realm.getDefaultInstance();
    MyRepository repository = MyRepository(realm);
    repository.getAll()
    // ...