Concurrent Modification Exception : adding to an ArrayList

前端 未结 10 903
醉梦人生
醉梦人生 2020-11-22 10:53

The problem occurs at

Element element = it.next();

And this code which contains that line, is inside of an OnTouchEvent

相关标签:
10条回答
  • 2020-11-22 11:31

    I normally use something like this:

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

    quick, clean and bug-free

    another option is to use CopyOnWriteArrayList

    0 讨论(0)
  • 2020-11-22 11:31

    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);
       }
    }
    
    0 讨论(0)
  • 2020-11-22 11:32

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

    0 讨论(0)
  • 2020-11-22 11:34

    Using Iterators also fixes concurrency problems, like this:

    Iterator<Object> it = iterator.next().iterator();
    while (it.hasNext()) {
        it.remove();
    }
    
    0 讨论(0)
提交回复
热议问题