Удаление объектов из списка массивов — исключение параллельной модификации

Я делаю игру, и я прочитал все об исключении одновременной модификации при удалении/изменении списка массивов во время итерации по нему, но у меня все еще есть проблема.
Я хочу удалить объект при касании экрана и объекты x, y выравнивается с затронутым x, y, но когда это происходит, я помещаю этот затронутый объект в новую коллекцию для удаления, но он удаляет (иногда) объект, но через 3-4 секунды, что не имеет для меня особого смысла, а также дает исключение одновременной модификации через 10-15 секунд. Если кто-нибудь заметит что-нибудь в моем коде, дайте мне знать...

public void checkTouch(MotionEvent arg1) {
        int x = (int) arg1.getX();
        int y = (int) arg1.getY();
        synchronized(surfaceHolder){
        /*check every creature for the coordinates*/
        Iterator<Sprite> it = creature.iterator();
        while(it.hasNext())
        {
            Sprite current = it.next();
            int sglX = current.getX();
            int sglY = current.getY();
                if(sglX>=x && x<=(sglX+current.getWidth())){
                    if(sglY>=y && y<=(sglY-current.getHeight())){
                        destroy(current);
                        break; //when we found one object, don't iterate no more
                    }
                }

            }
        }
    }

И метод уничтожения:

 private void destroy(Sprite removed) {
        /*adds the creature clicked to the recicle bin to be destroyed*/
        recicle.add(removedSeagull); //recicle is the other collection
    }

И я называю это creature.removeAll(recicle); перед тем, как рисовать существ на холсте, чтобы он не конфликтовал с другим итератором. Вот трассировка стека:

07-11 21:06:00.905: E/AndroidRuntime(14221): FATAL EXCEPTION: Thread-83
07-11 21:06:00.905: E/AndroidRuntime(14221): java.util.ConcurrentModificationException
07-11 21:06:00.905: E/AndroidRuntime(14221):    at                  java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)
07-11 21:06:00.905: E/AndroidRuntime(14221):    at   com.example.creatures.GameView$GameThread.drawCreatures(GameView.java:292)
07-11 21:06:00.905: E/AndroidRuntime(14221):    at com.example.creatures.GameView$GameThread.doDraw(GameView.java:283)
07-11 21:06:00.905: E/AndroidRuntime(14221):    at com.example.creatures.GameView$GameThread.run(GameView.java:245)

Я подумал, что это может быть метод рисования, так что, возможно, ошибка здесь, вот она:

private void drawCreatures(Canvas c) {
        /*iterate through the array and update all the creatures*/
        synchronized(surfaceHolder){
        Iterator<Sprite> it = creature.iterator();
        while(it.hasNext())
        {
            Sprite current = it.next();
            current.draw(c);
        }
        }
    }

И метод запуска GameThread вызывается в GameView (который расширяет держатель поверхности) следующим образом:

 @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        thread.setRunning(true);
        thread.start();
    startTimer(1500);
}

А также метод запуска потока таков:

@Override
    public void run(){
        while(run){
            Canvas c = null;
            try {
                c = surfaceHolder.lockCanvas(null);
                synchronized (surfaceHolder) {
                    if (mode == STATE_RUNNING){
                        doDraw(c);
                    }
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    /*unlocks the canvas and shows the image drawn by the doDraw method*/
                    surfaceHolder.unlockCanvasAndPost(c);
                }

Метод drawCreatures вызывается в методе doDraw.


person Pavle37    schedule 11.07.2014    source источник
comment
Может проблема не в нем. Предоставьте свой метод drawCreatures, пожалуйста. И где вы называете метод запуска вашего GameView?   -  person Eldar Miensutov    schedule 12.07.2014
comment
Смотри теперь дружище (:   -  person Pavle37    schedule 12.07.2014


Ответы (2)


Если вы согласны с устаревшими результатами итератора, вы можете использовать CopyOnWriteArrayList http://developer.android.com/reference/java/util/concurrent/CopyOnWriteArrayList.html

В основном это гарантирует, что итератор показывает содержимое, которое присутствовало во время создания итератора. Единственное изменение состоит в том, что iterator.remove() не будет работать с итераторами, возвращаемыми этим списком. Вы должны удалить его из фактического списка.

Надеюсь, это поможет,

Нагеш

person Nagesh Susarla    schedule 11.07.2014

Почему вы не используете метод iterator по умолчанию?

Пишите it.remove() вместо destroy(current);

person Eldar Miensutov    schedule 11.07.2014
comment
Конечно, я пробовал, но это не помогает, получаю то же сообщение. - person Pavle37; 11.07.2014
comment
Хорошо, предоставьте, пожалуйста, трассировку стека. - person Eldar Miensutov; 11.07.2014