android animation concurrentmodification

java.util.ConcurrentModificationException en la animación de Android



animation (4)

Hay algo que extraño con la noción de Sincronizar el código en Android.

Guión

Siempre hay 3 elementos dibujados en la pantalla. Cada imagen se almacena en una ArrayList (lstGraphics). Para este propósito, uso SurfaceView. Una vez que el usuario toque una imagen, se eliminará el mercado de obtención de imagen y se agregará uno nuevo.

Muestras de código:

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); } } } } ...

Para que pueda parecer primero, actualizo la Física (). Esto significa que calculo la dirección hacia donde se moverá cada imagen. Aquí también eliminaré las imágenes clicadas de mi lista. Después de eso, verifico si necesito agregar un nuevo ítem en mi lista en manageAnimations () y luego el último paso dibujar todo.

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

El error que recibo es:

> 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)

Cualquier ayuda es muy apreciada. Gracias.


Como dijo @idefix, puede obtener fácilmente ConcurrentModificationException en un contexto de subproceso único como este:

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


Este es mi método usando la segunda solución de @idefix:

private List<TYPE> getFilteredData(List<TYPE> data){ List<TYPE> toRemove = new ArrayList<TYPE>(data.size()); synchronized(data){ for(TYPE f : data){ if([CONDITION]){ toRemove.add(f); Log.w(TAG, "Element removed: "+ f); } } } data.removeAll(toRemove); return data; }

Gracias @idefix +1


Puede usar CopyOnWriteArrayList como a continuación:

List<String> myList = new CopyOnWriteArrayList<String>(); myList.add("1"); myList.add("2"); myList.add("3"); myList.add("4"); myList.add("5"); Iterator<String> it = myList.iterator(); while(it.hasNext()){ String value = it.next(); System.out.println("List Value:"+value); if(value.equals("3")){ myList.remove("4"); myList.add("6"); myList.add("7"); } }


Su problema está en su método de física, donde agrega el gráfico y la lista

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

la combinación de for(Graphic graphic : lstGraphics) y lst.Graphics.remove(graphic); causa la excepción ConcurrentModificationException porque está ejecutando su lista y al mismo tiempo intenta modificarla.

Hasta ahora sé dos soluciones:

  1. Use un iterador en su lugar si uno está disponible (nunca codificado para Android hasta el momento).

    while (iter.hasNext) { if (physicsCondition) iter.remove(); }

  2. use una segunda lista para almacenar los elementos para eliminar y eliminarlos después

    List<GraphicsItem> toRemove = new .... for (Graphic graphic : lstGraphics) { if (physicsCondition) { toRemove.add(graphic); } } lstGraphics.removeAll(toRemove);