Reputation: 1034
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
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
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
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
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