Realm-java: RxJava + delete data, async problems

Created on 7 Jul 2016  路  4Comments  路  Source: realm/realm-java

Hello.
I want to fetch data from table by one row, do some operations and if it's ok delete this row.

my code is

final Realm realm = Rlm.getInstance(Rlm.Db.Analytics);
realm.where(AnalyticsQueue.class).findAllAsync().asObservable()
                .filter(new Func1<RealmResults<AnalyticsQueue>, Boolean>() {
                    @Override
                    public Boolean call(RealmResults<AnalyticsQueue> analyticsQueues) {
                        return analyticsQueues.isLoaded();
                    }
                })
                .flatMap(new Func1<RealmResults<AnalyticsQueue>, Observable<AnalyticsQueue>>() {
                    @Override
                    public Observable<AnalyticsQueue> call(RealmResults<AnalyticsQueue> analyticsQueues) {
                        return Observable.from(analyticsQueues);
                    }
                }).doOnUnsubscribe(new Action0() {
                    @Override
                    public void call() {
                        if (!realm.isClosed()){
                            realm.close();
                        }
                    }
                })

.....

.subscribe(new Action1<AnalyticsQueue>() {
                    @Override
                    public void call(final AnalyticsQueue analyticsQueue) {
                        // some code
                        if (ok){
                            // there is three variants of code, listed below
                        }
                    }
                });
    1.
event.deleteFromRealm();
//  rx.exceptions.OnErrorNotImplementedException: Changing Realm data can only be done from inside a transaction.

2.

final Realm realm = Rlm.getInstance(Rlm.Db.Analytics);
realm.beginTransaction();
analyticsQueue.deleteFromRealm();
realm.commitTransaction();
// W/REALM: Mixing asynchronous queries with local writes should be avoided. Realm will convert any async queries to synchronous in order to remain consistent. Use asynchronous writes instead. You can read more here: https://realm.io/docs/java/latest/#asynchronous-transactions

3.

final Realm realm = Rlm.getInstance(Rlm.Db.Analytics);
realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                event.deleteFromRealm();
            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable error) {
                error.printStackTrace();
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        });
// java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.

So, how can I solve my problem?

T-Help

Most helpful comment

In 3), if you do

final Realm realm = Rlm.getInstance(Rlm.Db.Analytics);
final String id = event.getId();
realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.where(AnalyticsQueue.class).where("id", id).findFirst().deleteFromRealm();
            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable error) {
                error.printStackTrace();
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        });

It should work.

All 4 comments

As the warning says, if you use the async API, then you shouldn't be making synchronous writes.

If you want to do synchronous writes, then you should use the sync API for the query:

realm.where(AnalyticsQueue.class).findAll().asObservable()

And then use the 2) proposition with begin/commit replaced by executeTransaction(), without the additional getInstance() call.

I'm also thinking about how you could create an Observable on the io() scheduler that creates a Realm and passes it along in a tuple (like android.util.Pair) and then closes it, but it's just a vague idea and I can't seem to get it right (I don't really use Rx). That way you could bring the deletion to a definite background thread.

In 3), if you do

final Realm realm = Rlm.getInstance(Rlm.Db.Analytics);
final String id = event.getId();
realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.where(AnalyticsQueue.class).where("id", id).findFirst().deleteFromRealm();
            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable error) {
                error.printStackTrace();
                if (!realm.isClosed()) {
                    realm.close();
                }
            }
        });

It should work.

Thanks for your replies, I resolve my problem.

@morder

It's great to hear your issue is resolved. I'm closing this for now. When the issue arises again, please reopen it. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tloshi picture tloshi  路  3Comments

David-Kuper picture David-Kuper  路  3Comments

wyvern610 picture wyvern610  路  3Comments

Merlin1993 picture Merlin1993  路  3Comments

wezley98 picture wezley98  路  3Comments