I already gone through these similar questions for the issue, but could not find the answer
SO question1 , SO question2 and SO question3
My application flow is on button click, network is requested as follows using Volley
. Included only relevant code . Error getting in ActivityCustomer
in the following line
Object obj = realmObj.where(ExplorerFolderData.class)
.equalTo(Constants.DBPARENTID,"0")
.or()
.equalTo(Constants.DBPARENTID,"-1")
.findAllAsync();
Error:
Caused by: java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
1) MyApplication
public class MyApplication extends Application
{
private static Context appContext;
@Override
public void onCreate() {
super.onCreate();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(0)
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);
appContext = getApplicationContext();
}
public static Context getAppContext(){
return appContext;
}
}
2) Interface OnAsyncTaskComplition
//This interface will get back the status to Activity/Fragment
public interface OnAsyncTaskComplition {
public void networkResponse(ResultObject responseObject);
}
3) NetworkProcessor
public class NetworkProcessor{
private OnAsyncTaskComplition mCaller;
public NetworkProcessor(Activity activity){
//setting caller Activity/Fragment to get back data
mCaller=(OnAsyncTaskComplition)activity;
processNetworkData();
}
//Method for Volley Network Procesing
public void processNetworkData(){
JsonObjectRequest jsonObjReq = new JsonObjectRequest(methodReq,urlBuffer.toString(),null,
new Response.Listener<JSONObject>(){
@Override
public void onResponse(JSONObject response) {
JsonProcessor jsonProcessor=new JsonProcessor();
mCaller.networkResponse(jsonProcessor.getThingList(response));
}
}, new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
//Handle error also back to caller
}
});
}
}
4) JsonProcessor
public class JsonProcessor {
public status void getThingList(JSONObject response){
boolean status=false;
try{
RealmProcessor realmProcessor=RealmProcessor.with(MyApplication.getAppContext());
Realm realmObj = realmProcessor.getRealm();
//Code for setting values to RealmObject class ExplorerFolderData
realmObj.beginTransaction();
realmObj.copyToRealm(ExplorerFolderData RealmObject which has values populated);
realmObj.commitTransaction();
status=true;
}catch(Exception e){
}
}
}
5) RealmProcessor
public class RealmProcessor {
private static RealmProcessor instance;
private Realm realm;
private RealmProcessor(Context context) {
realm = Realm.getDefaultInstance();
}
public static RealmProcessor with(Context context) {
if (instance == null) {
instance = new RealmProcessor(context);
}
return instance;
}
public Realm getRealm() {
return realm;
}
}
6) Activity class ActivityCustomer
public class ActivityCustomer extends AppBaseActivity implements OnAsyncTaskComplition
{
//Method called on Button click
private void callNetwork(){
new NetworkProcessor(this);
}
@Override
public void networkResponse(ResultObject responseObject) {
new ExplorerDBOperation().execute();
}
class ExplorerDBOperation extends AsyncTask<Void,Boolean,Boolean> {
ProgressDialog dialog;
@Override
protected Boolean doInBackground(Void... params) {
RealmProcessor realmProcessor=RealmProcessor.with(MyApplication.getAppContext());
Realm realmObj = realmProcessor.getRealm();
//ERROR OVER HERE
Object obj = realmObj.where(ExplorerFolderData.class)
.equalTo(Constants.DBPARENTID,"0")
.or()
.equalTo(Constants.DBPARENTID,"-1")
.findAllAsync();
return true;
}
}
I am getting realm object using the same line in Activity as well as JsonProcessor class. What is the mistake I am making over here.
The way you are set up with the singleton you have only 1 Realm instance.
If you call realmProcessor.getRealm();
in thread A, and then call it again in thread B, they get back the same instance. Realm does not allow sharing instances between threads. Since the AsyncTask's doInBackground runs on a separate thread, this is not working.
Changing to this will rid you of the error. However you have some redesigning to do.
@Override
protected Boolean doInBackground(Void... params) {
Realm realmObj = Realm.getDefaultInstance();
try {
Object obj = realmObj.where(ExplorerFolderData.class)
.equalTo(Constants.DBPARENTID,"0")
.or()
.equalTo(Constants.DBPARENTID,"-1")
.findAll();
} catch (Exception ex) {
// handle error
} finally {
realmObj.close();
}
return true;
}
Note that you are responsible for each and every realm instance. This means that you must manually ensure that you close every instance once you're done with it. A common practice for AsyncTasks is that you wrap your doInBackground operations in a try/catch/finally and close the realm instance in the finally block to ensure it gets closed.
See more in the docs