Search code examples
javaandroidandroid-asynctaskrealmconcurrentmodification

Concurrent Modification Exception Writing to Realm in onPostExecute method - Android


I am using Realm as my Database. And while inserting/updating the data I am getting the following error

FATAL EXCEPTION: main
Process: uk.org.humanfocus.hfi, PID: 6430
 java.util.ConcurrentModificationException
 at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
  at org.json.JSONArray.writeTo(JSONArray.java:612)
  at org.json.JSONStringer.value(JSONStringer.java:233)
  at org.json.JSONObject.writeTo(JSONObject.java:720)
  at org.json.JSONObject.toString(JSONObject.java:689)
  at uk.org.humanfocus.hfi.DriverBehavior.DriverBehaviorMap$InsertCarProbeData.onPostExecute(DriverBehaviorMap.java:252)
  at uk.org.humanfocus.hfi.DriverBehavior.DriverBehaviorMap$InsertCarProbeData.onPostExecute(DriverBehaviorMap.java:229)
  at android.os.AsyncTask.finish(AsyncTask.java:651)
  at android.os.AsyncTask.-wrap1(AsyncTask.java)
  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5443)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

Unlike others I am not doing it in the for loop, instead I am doing it in the onPostExecute method of AsyncTask which is called from location changed listener. Neither is it being used somewhere else.

private class InsertCarProbeData extends AsyncTask<Void, Void, Void> {

    Location location;

    public InsertCarProbeData(Location location) {
        this.location = location;
    }

    @Override
    protected Void doInBackground(Void... params) {
        try {
            addObjectToJSONArray(location);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        realm.beginTransaction();
        trip.json = tripJSON.toString();
        realm.commitTransaction();
    }
}

And this AsyncTask is being called from here

new InsertCarProbeData(location).execute();

Solution

  • There is several problens in your code:

    1) you store all values inside JSONArray, that means, it will attempt to wtite ALL PREVIOUS values too. When array grow large, new data arraive while old values is still bein processed - that is reason of error

    2) .onPostExecute() method is executed on main thread, so by doing so, you have no benefit of AsyncTask.

    3) AsyncTask is obsolete and is shares the same thread pool (with the same proirity, as main thread)

    There is similar answer, look into it: Writing realm from service class causing UI block