Realm对象只能在创建它们的线程上访问_ Volley和AsyncTask(Realm objects can only be accessed on the thread they were created _ Volley and AsyncTask)

我已经解决了这个问题的类似问题,但找不到答案

所以问题1 , 问题2和问题3

我的应用程序流程是按钮点击,使用Volley按如下方式请求网络。 只包括相关的代码。 在以下行中访问ActivityCustomer时出错

Object obj = realmObj.where(ExplorerFolderData.class) .equalTo(Constants.DBPARENTID,"0") .or() .equalTo(Constants.DBPARENTID,"-1") .findAllAsync();

错误:

由:java.lang.IllegalStateException引起:Realm从不正确的线程访问。 领域对象只能在创建它们的线程上访问。

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)接口OnAsyncTaskComplition

//This interface will get back the status to Activity/Fragment public interface OnAsyncTaskComplition { public void networkResponse(ResultObject responseObject); }

3) 网络处理器

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

我在Activity和JsonProcessor类中使用相同的行获取领域对象。 我在这里犯了什么错误。

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.

最满意答案

你使用单例设置的方式只有1个Realm实例。

如果你调用realmProcessor.getRealm(); 在线程A中,然后在线程B中再次调用它们,它们返回相同的实例。 Realm不允许在线程之间共享实例。 由于AsyncTask的doInBackground在单独的线程上运行,因此这不起作用。

更改为此将消除错误。 但是你有一些重新设计要做。

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

请注意,您负责每个领域实例。 这意味着您必须手动确保您完成每个实例后关闭它。 AsyncTasks的一个常见做法是将doInBackground操作包装在try / catch / finally中,并关闭finally块中的realm实例以确保它被关闭。

在文档中查看更多内容

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

更多推荐