Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.util.ConcurrentModificationException in Android animation

Tags:

There is something I miss with the notion of Synchronizing code in Android.

Scenario

There are always 3 items drawn on the screen. Each image is stored in a ArrayList (lstGraphics). For this purpose I use a SurfaceView. Once the user taps on a image, the image get's market to be removed and a new one will be added.

Code samples:

AnimationHideThread

...     @Override         public void run() {             Canvas c;             while (run) {                 c = null;                 try {                     c = panel.getHolder().lockCanvas(null);                       synchronized (panel.getHolder()) {                          panel.updatePhysics();                         panel.manageAnimations();                         panel.onDraw(c);                      }                 } finally {                     if (c != null) {                         panel.getHolder().unlockCanvasAndPost(c);                     }                 }             }         }     ... 

So as you can seem first I updatePhysics(). This means I calculate direction where each image will move to. In here I will also remove clicked images from my list. After that I check if I need to add a new Item in my list in manageAnimations() and then the final step draw the whole thing.

public class Panel extends SurfaceView implements SurfaceHolder.Callback { ....  public void manageAnimations()     {           synchronized (this.getHolder()) {             ...         while (lstGraphics.size()<3) {                 lstGraphics.add(createRandomGraphic());                 }         }           }     }   @Override     public boolean onTouchEvent(MotionEvent event) {          synchronized (getHolder()) {             if (event.getAction() == MotionEvent.ACTION_DOWN) {                  //... check if a image has been clicked and then set its property                         graphic.setTouched(true);                   }             }              return true;          }     }   public void updatePhysics() {        synchronized (getHolder()) {       for (Graphic graphic : lstGraphics) {            //.... Do some checks      if (graphic.isTouched())       {         lstGraphics.remove(graphic);       }      }   }  }   @Override     public void onDraw(Canvas canvas) {          /// draw the backgrounds and each element from lstGraphics }  public class Graphic {          private Bitmap bitmap;             private boolean touched;             private Coordinates initialCoordinates;  .... } 

The error I get is:

> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): Uncaught handler: thread Thread-12 exiting due to uncaught exception  > 03-01 10:01:53.365: ERROR/AndroidRuntime(454): java.util.ConcurrentModificationException > 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:66) > 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at com.test.customcontrols.Panel.updatePhysics(Panel.java:290) > 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at com.test.customcontrols.AnimationHideThread.run(AnimationHideThread.java:41) 

Any help is greatly appreciated. Thank you.

like image 432
Alin Avatar asked Mar 01 '11 08:03

Alin


People also ask

What is Java Util ConcurrentModificationException?

The java. util. concurrentmodificationexception is an error in Java. The error occurs when the iterator is traversing a list, and a command is used to change an element's value during that traversal.

How do I overcome Java Util ConcurrentModificationException?

How do you fix Java's ConcurrentModificationException? There are two basic approaches: Do not make any changes to a collection while an Iterator loops through it. If you can't stop the underlying collection from being modified during iteration, create a clone of the target data structure and iterate through the clone.

Who throws ConcurrentModificationException?

Class ConcurrentModificationException. This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible. For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it.


2 Answers

Your problem is in your physics method, where you add the graphic and the list

public void updatePhysics() {     synchronized (getHolder()) {         for (Graphic graphic : lstGraphics) {         //.... Do some checks         if (graphic.isTouched()) {             lstGraphics.remove(graphic); //your problem         }     } } 

the combination of for(Graphic graphic : lstGraphics) and lst.Graphics.remove(graphic); causes the ConcurrentModificationException because you are running over your list and concurrently try to modify it.

So far I know two solutions:

  1. Use an Iterator instead if one is available (never coded for Android so far).

    while (iter.hasNext) {     if (physicsCondition) iter.remove(); } 
  2. use a second list to store the elements to remove and remove them afterwards

    List<GraphicsItem> toRemove = new .... for (Graphic graphic : lstGraphics) {     if (physicsCondition) {         toRemove.add(graphic);     } } lstGraphics.removeAll(toRemove); 
like image 191
monty Avatar answered Oct 29 '22 20:10

monty


As @idefix said, you can easily get ConcurrentModificationException in single-threaded context like this:

public static void main(String[] args) {     List<String> list = new ArrayList<String>(Arrays.asList("AAA", "BBB"));     for (String s : list) {         if ("BBB".equals(s)) {             list.remove(s);         }     } } 
like image 31
denis.solonenko Avatar answered Oct 29 '22 19:10

denis.solonenko