The problem occurs at
Element element = it.next();
And this code which contains that line, is inside of an OnTouchEvent
I normally use something like this:
for (Element element : new ArrayList<Element>(mElements)) {
...
}
quick, clean and bug-free
another option is to use CopyOnWriteArrayList
The accepted solution (to create a copy of the collection) usually works well.
However, if the Element
contains another collection this does not make a deep copy!
Example:
class Element {
List<Kid> kids;
getKids() {
return kids;
}
}
Now when you create a copy of the List of Elements:
for (Element element : new ArrayList<Element>(elements)) { ... }
You can still get a ConcurrentModificationException
if you iterate over element.getKids()
and, parally, alter the kids
of that element.
Looking back it's obvious, but I ended up in this thread so maybe this hint helps others, too:
class Element {
List<Kid> kids;
getKids() {
// Return a copy of the child collection
return new ArrayList<Kid>(kids);
}
}
adding from list in this case leads to CME, no amount of synchronized
will let you avoid that. Instead, consider adding using the iterator...
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;
}
}
}
Also I think it's somewhat slippery to state like...
...The problem occurs at
Element element = it.next();
for the sake of precision note that above is not guaranteed.
API documentation points out that this ...behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis...
Using Iterators also fixes concurrency problems, like this:
Iterator<Object> it = iterator.next().iterator();
while (it.hasNext()) {
it.remove();
}