Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This Realm instance has already been closed, making it unusable + RxJava

Tags:

android

realm

First of all i manage realm instance by Repository class:

public class RealmRepository {

private Lock lock;

protected RealmRepository() {
    lock = new ReentrantLock();
}

public  <T> T execute(Executor<T> executor) {
    Realm realm = null;
    try {
        lock.lock();
        realm = Realm.getDefaultInstance();
        return executor.execute(realm);
    } finally {
        if (realm != null && !realm.isClosed()) {
            realm.close();
        }
        lock.unlock();
    }
}

public interface Executor<T> {
    T execute(Realm realm);
}
}

And the only class that extends by this RealmRepository, this is my controller class. Problem is when i do at first time execute method in my fragment i got:

java.lang.IllegalStateException: This Realm instance has already been closed, making it unusable.

But after this error if reload fragment all works fine. And before this first fragment execute method calling from Services classes and works well. For example: This method works perfectly even when execute it first:

public Observable<ModuleRealm> getModule(String moduleTitle) {
    return execute(realm -> realm.where(ModuleRealm.class)
            .equalTo("code", moduleTitle)
            .findAllAsync()
            .asObservable()
            .first()
            .map(RealmResults::first));
}

But this one throws an exception:

public Observable<List<ProductCategoryRealm>> getProductCategories() {
    return execute(realm -> realm.where(ProductCategoryRealm.class)
            .findAll()
            .asObservable()
            .first()
            .map(realm::copyFromRealm));
}
like image 592
Drake Avatar asked Jan 03 '17 16:01

Drake


2 Answers

Realm instances are reference counted after the initial initialization call. Each call to close() decrements this reference count, and each call to getDefaultInstance() will increase this reference count. Realm's resources are freed once the reference count reaches 0.

Considering the fact that you're using a Lock to block accesses to your Realm instance, you're causing reference count to reach 0 when you make your close() call, then not reinitializing the Realm configuration after Realm has already freed its resources.

In order to fix this, you need your calls to getDefaultInstance() to overlap before the subsequent call to close() to ensure that your reference count remains > 0 while you're still actively using Realm, otherwise you need to reinitialize the entire Realm configuration each time which will come with a performance impact.

like image 63
Submersed Avatar answered Nov 17 '22 08:11

Submersed


The finally method will be executed before the calling method gets the result, in this case.

like image 41
Andrew Kochura Avatar answered Nov 17 '22 08:11

Andrew Kochura