Функцию onDraw ConcurrentModification андроид ()


У меня проблема с приложением для android.

У меня есть поток, который постоянно перебирает список или фигуры, обновляет их позиции и иногда удаляет элемент из списка. В конце цикла while потока он вызывает postInvalidate (), чтобы вызвать перерисовку.

Вот код, в котором происходит модификация ArrayList.

Iterator<Shape> iterator = this.myList.iterator();
while (iterator.hasNext()) {
     Shape nextShape = iterator.next();
     nextShape.move();
     if(condition) {
         iterator.remove()
     }
}

Метод onDraw использует цикл for each для рисования каждого из этих элементов. Я получаю параллельную модификацию в метод onDraw, несмотря только на изменение списка через итератор. Я пробовал CopyOnWriteArrayList и Collections.синхронизировано с теми же результатами.

Любая помощь будет признательна.

1 2

1 ответ:

Есть несколько способов решить эту проблему. Можно было бы использовать синхронизированный блок в потоке и в onDraw, но это помешало бы 2-му потоку работать одновременно с потоком пользовательского интерфейса.

Я думаю, что лучший способ для вас-использовать две коллекции. Ваш код должен выглядеть следующим образом
onDraw(){
    synchronized(myList){
        //Do your draw code.  Get the iterator inside this block
    }
}

threadFunction(){
    List threadList;
    while(1){
        //Update threadList, which holds all the objects
        synchronized(myList){
            myList = threadList.copy();  //Do a deep copy, don't just copy over the reference
        }
        postInvalidate();
    }
}

Это заставит вашу функцию draw работать с копией списка, сделанного в конце итерации. Если вы работаете с глубокой копией, у вас не будет никаких проблем с синхронизацией поскольку поток не изменяет один и тот же список. Синхронизированные блоки остановят поток от перезаписи копии функции draw во время рисования. Единственная оставшаяся проблема заключается в том, что перезапись списка в потоке будет висеть до тех пор, пока не будет выполнена ничья, но поскольку обновление его чаще, чем это, все равно не будет отображаться на экране, я думаю, что это приемлемо.