java android exception arraylist iteration

java - Excepción de modificación concurrente: agregar a una ArrayList



android exception (7)

Bueno, he intentado todos los aspectos en mi caso donde estaba iterando en una lista de adaptadores, pero debido a los golpes una y otra vez, me mostró el mensaje de excepción que se lanza. Intenté lanzar la lista a

= (CopyOnWriteArraylist<MyClass>)mylist.value;

pero también me arrojó una excepción de CouldNotCastException, (y finalmente reflexioné sobre el hecho de que por qué usan o nos proporcionan una fachada de casting).

Incluso utilicé el llamado Bloque Sincronizado también, pero incluso no funcionó o podría haberlo usado de forma incorrecta.

Por lo tanto, es todo cuando finalmente utilicé la # técnica de #todo de tiempo # para manejar la excepción en el bloque try catch, y funcionó. Así que pon tu código en el

try{ //block }catch(ConcurrentModificationException){ //thus handling my code over here }

El problema ocurre en

Element element = it.next();

Y este código que contiene esa línea, está dentro de un OnTouchEvent

for (Iterator<Element> it = mElements.iterator(); it.hasNext();){ Element element = it.next(); if(touchX > element.mX && touchX < element.mX + element.mBitmap.getWidth() && touchY > element.mY && touchY < element.mY + element.mBitmap.getHeight()) { //irrelevant stuff.. if(element.cFlag){ mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY)); element.cFlag = false; } } }

Todo esto está dentro synchronized(mElements) , donde mElements es un ArrayList<Element>

Cuando toco un Element , puede activar cFlag , que creará otro Element con diferentes propiedades, que se caerá de la pantalla y se destruirá a sí mismo en menos de un segundo. Es mi forma de crear efectos de partículas. Podemos llamar a esta crack "partículas", como el parámetro String en el constructor.

Todo esto funciona bien hasta que agregue otro Element principal. Ahora tengo dos Elements en la pantalla al mismo tiempo, y si toco el Element más nuevo, funciona bien y lanza las partículas.

Sin embargo, si toco y activo cFlag en el Element anterior, entonces me da la excepción.

07-28 15:36:59.815: ERROR/AndroidRuntime(4026): FATAL EXCEPTION: main 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): java.util.ConcurrentModificationException 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.Juggle2.Panel.onTouchEvent(Panel.java:823) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.View.dispatchTouchEvent(View.java:3766) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1767) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1119) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.app.Activity.dispatchTouchEvent(Activity.java:2086) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1751) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewRoot.handleMessage(ViewRoot.java:1785) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.os.Handler.dispatchMessage(Handler.java:99) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.os.Looper.loop(Looper.java:123) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.app.ActivityThread.main(ActivityThread.java:4627) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.lang.reflect.Method.invokeNative(Native Method) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.lang.reflect.Method.invoke(Method.java:521) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:651) 07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at dalvik.system.NativeStart.main(Native Method)

¿Cómo puedo hacer que esto funcione?


El uso de Iterators también soluciona problemas de concurrencia, como este:

Iterator<Object> it = iterator.next().iterator(); while (it.hasNext()) { it.remove(); }


No puede agregar una entrada a una colección mientras la itera.

Una opción es crear un nuevo List<Element> para nuevas entradas mientras itera sobre mElements , y luego agrega todas las nuevas a mElement después ( mElements.addAll(newElements) ). Por supuesto, eso significa que no habrá ejecutado el cuerpo del bucle para esos nuevos elementos, ¿es eso un problema?

Al mismo tiempo, recomiendo que actualice su código para usar el bucle for mejorado :

for (Element element : mElements) { ... }


Normalmente uso algo como esto:

for (Element element : new ArrayList<Element>(mElements)) { ... }

rápido, limpio y libre de errores

otra opción es usar CopyOnWriteArrayList


Un bucle indexado también debería funcionar.

for (int i = 0; i < collection.size(); i++)


agregar de la lista en este caso conduce a CME, ninguna cantidad de synchronized le permitirá evitar eso. En su lugar, considere agregar usando el iterador ...

for(ListIterator<Element> it = mElements.listIterator(); it.hasNext();){ Element element = it.next(); if(touchX > element.mX && touchX < element.mX + element.mBitmap.getWidth() && touchY > element.mY && touchY < element.mY + element.mBitmap.getHeight()) { //irrelevant stuff.. if(element.cFlag){ // mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY)); it.add(new Element("crack",getResources(), (int)touchX,(int)touchY)); element.cFlag = false; } } }

También creo que es algo resbaladizo decir como ...

... El problema ocurre en Element element = it.next();

por el bien de la precisión, tenga en cuenta que lo anterior no está garantizado.

ConcurrentModificationException señala que este ... comportamiento no se puede garantizar ya que, en términos generales, es imposible hacer ninguna garantía dura en presencia de modificaciones concurrentes no sincronizadas. Las operaciones de falla rápida lanzan ConcurrentModificationException sobre una base de mejor esfuerzo ...


ConcurrentModificationException produce cuando modifica la lista (agregando o eliminando elementos) al atravesar una lista con Iterator .

Tratar

List<Element> thingsToBeAdd = new ArrayList<Element>(); for(Iterator<Element> it = mElements.iterator(); it.hasNext();) { Element element = it.next(); if(...) { //irrelevant stuff.. if(element.cFlag){ // mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY)); thingsToBeAdd.add(new Element("crack",getResources(), (int)touchX,(int)touchY)); element.cFlag = false; } } } mElements.addAll(thingsToBeAdd );

También debería considerar mejorar para cada ciclo como Jon sugirió.