11 March 2013

How to solve problem with ConcurrentModificationException in Android?

  STORY:
I am in the middle of creating prototype for my RPG game.
It is turn based so after turn I have method that update info.
For example if some state are expired I want remove them.
So, I wrote something like that:
  for(TemporaryAtribute ta : tempAttrs){
    ta.turnleft -= 1;
    if(ta.turnleft <= 0){
      tempAttrs.remove(ta);
      msg += ta.attr.toString() + "is removed.\n";
    }
  }

Unfortunately.Red line cause a problem as
tempAttrs.remove(ta);  throws a  ConcurrentModificationException.

Which looks like:
03-11 22:12:47.425: ERROR/AndroidRuntime(23348): FATAL EXCEPTION: main
java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)
(...)
at android.view.View.performClick(View.java:4101)
at android.view.View$PerformClick.run(View.java:17078)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5493)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795)
at dalvik.system.NativeStart.main(Native Method)
I never seen this Exception,so  I looked to oracle for information about this :
"This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible."
 Hmm... They wrote even more ...

"For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it."
Oh ,dear. It seems, you cannot remove something from collection during iterating over it. Not good,but how to solve my case?

SOLUTION:

Well, what i have done.I  change my code to:
  ArrayList<TemporaryAtribute> temp = new ArrayList<TemporaryAtribute>();
  for(TemporaryAtribute ta : tempAttrs){
    ta.turnleft -= 1;
    if(ta.turnleft <= 0){
      temp.add(ta);
    }
  }
if(temp.size() >0){
   for(TemporaryAtribute tempa : temp){
     tempAttrs.remove(tempa);
     msg += tempa.attr.toString() + "is removed.\n";
   }

}
What I have done is instead of removing directly during iteration. I collect them in... other collection  and then remove collected items from original collection.
It works.
I am not sure is it right way of do,but it works!
Why I am not sure? As I think for very large collection,it can be a performance issue,but for my purpose it is perfectly fine


Source: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ConcurrentModificationException.html