Jemshit
Jemshit

Reputation: 10058

Realm access inside Rx Observable error

I'm getting error when i try to make operation on realm instance as like below:

.flatMap(h -> Observable.from(h.getEntityDataList())).filter(p -> p.isMyProfile())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<ProfileView>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    Log.v("test", "error: " + e.toString());
                }

                @Override
                public void onNext(ProfileView profileView) {                        
                    realmManager.saveActiveUser(gson.toJson(profileView));
                   //...
                }
            });

RealmManager:

public class RealmManager{
    private Realm realm;

    public RealmManager(){
        realm = Realm.getDefaultInstance();
    }

    public void saveActiveUser(String json)}{
        realm...
    } 

Code enters to onError() above showing realm objects can only be accessed on the thread they were created. I am injecting RealmManager into first code with Dagger.

How to overcome this ? And what is the best practice to make RealmManager class? Should i make RealmManager singleton (and realm object static) and access it everywhere? Should i make it like above and inject it whenever i want?

EDIT: i'm injecting RealmManager instance which is provided in Application Component which is Singleton.

Upvotes: 0

Views: 593

Answers (1)

Ilya Tretyakov
Ilya Tretyakov

Reputation: 7010

Due to Realm-objects are live objects you can not get it on one thread (IO-thread) and use in another (main-thread). You could detach these objects by using next code (took from Realm's documentation):

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

Using Realm with Dagger is not so smooth as I want.

You should not forget to close Realm. Otherwise your app will be more likely get killed by the system (in case of low resources).

Realm.getInstance() creates instance for each thread. And you can't create Realm in one thread and use it in another.

I thing the best choice is using DI's scopes. But as a quick solution you could try Provider<Realm> realmProvider construction in dagger's module.

Upvotes: 2

Related Questions