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.
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 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.
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.
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:
Use an Iterator instead if one is available (never coded for Android so far).
while (iter.hasNext) { if (physicsCondition) iter.remove(); }
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);
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); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With