mahdi pishguy
mahdi pishguy

Reputation: 1034

Android how can i use Realm on Thread

In my application I read contacts which saved on phone, this may be take a long time, then I put that on Thread nested that I'm using Realm but I get this error:

Realm access from incorrect thread. 
Realm objects can only be accessed on the thread they were created.

And my solutions don't resolve this problem such as :

new Handler().post(new Runnable() {
    @Override
    public void run() {
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
            }
        });
    }
});

OR

new Handler(getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
            }
        });            
    }
});

on nested Thread,

Upvotes: 5

Views: 7096

Answers (4)

Aks4125
Aks4125

Reputation: 5720

Use try with resources within any thread. You don't need to close realm instance. It does close automatically.

try (Realm r = Realm.getDefaultInstance()) {
    r.executeTransaction(realm -> realm.insertOrUpdate(mData));
}

Upvotes: 1

EpicPandaForce
EpicPandaForce

Reputation: 81539

You need an instance on the given thread where you're trying to use the Realm instance.

new Handler(Looper.getMainLooper()).post(new Runnable() { // <-- if you are not on UI thread and want to go there
    @Override
    public void run() {
        Realm realm = null;
        try {
            realm = Realm.getDefaultInstance();
            realm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                }
            });
        } finally {
            if(realm != null) {
                realm.close();
            }
        }
    }
});

Although you shouldn't be doing synchronous writes on the UI thread. Use async transaction instead if you write on the UI thread.

new Handler(Looper.getMainLooper()).post(new Runnable() {  // <-- if you are not on UI thread and want to go there
    @Override
    public void run() {
          final Realm realm = Realm.getDefaultInstance();
          realm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                }
            }, 
            new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    realm.close();
                }
            }, 
            new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable e) {
                    realm.close();
                }
            });
    }
});

I personally prefer creating a single-threaded executor, on which Realm writes are done.

 private final Executor executor = Executors.newSingleThreadExecutor();

 ...

 executor.execute(() -> {
     try(Realm realm = Realm.getDefaultInstance()) {
         // use Realm on background thread
     }
 });

And for UI thread, you generally already have a Realm instance open/closed by either onCreate/onDestroy or onStart/onStop.

Upvotes: 7

Hasanuzzaman Mamun
Hasanuzzaman Mamun

Reputation: 166

You can now use Realm's very own asynchronous block to do the work.

realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                // Some working is here.
            }
        }, new Realm.Transaction.OnSuccess() {
            // Some proceesing lines are here.
        }, new Realm.Transaction.OnError() {
            Log.d("AsyncTransaction", "ERROR");
        });

Be aware that, in the execute(Realm realm) method, you need to use this realm object for all the transactions, not your global realm object.

Upvotes: 0

Budius
Budius

Reputation: 39836

The problem is not that you're using Realm in a different thread, the problem is that you're using the instance on the real in a different thread. Usually that's an easy fix, something like that should do:

Realm realmForThisThread = Realm.getDefaultInstance();
realmForThisThread.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
    }
}
...
realmForThisThread.close();

Upvotes: 3

Related Questions