我正在尝试将项添加到集合时出现ConcurrentModificationException

时间:2011-11-18 13:50:38

标签: java android

我花了一整天时间试图解决这个问题。我尝试使用itertaion?同步,以及许多其他shamanic方法,但我一直得到ConcurrentModificationException.Here代码。

package com.androidgui.test;

import java.util.ArrayList;
import java.util.ListIterator;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;

import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.widget.Toast;

public class CustomView extends SurfaceView implements Callback {
    private UpdateThread thread;
    private AButton btn;
    private AWindow wnd;
    private ArrayList<AControl> globalControls;
    private Object sync;
    public static int posX;
    public static int posY;

    public CustomView(Context context) {
        super(context);
        this.getHolder().addCallback(this);
        this.LoadResourse();
        sync =  new Object();
        this.globalControls = new ArrayList<AControl>();
        btn = new AButton(10, 10,null,AControl.InterfaceImages.Button); 
        this.globalControls.add(btn);
        wnd = new AWindow(10, 10, 200, 100, null);
        this.SetDelegates();

    }
    private void LoadResourse()
    {
        AControl.InterfaceImages.Button = BitmapFactory.decodeResource(getResources(), R.drawable.button);
    }
    private void SetDelegates()
    {
        btn.setEventHandler(new EventHandler() {

            @Override
            public void ProcessEvent() {
                synchronized (sync) {
                    globalControls.add(wnd);
                }
            }
        });
    }
    @Override
    public void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        posX = (this.getWidth()- AControl.InterfaceImages.Button.getWidth()) /2;
        posY = (this.getHeight()- AControl.InterfaceImages.Button.getHeight()) /2;
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        thread = new UpdateThread(this.getHolder(), this);
        thread.setRunning(true);
        thread.start();

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        thread.setRunning(false);
        boolean _retry=true;
        try
        {
        while(_retry)
        {
            thread.join();
            _retry=false;
        }
        }catch(Exception ex)
        {

        }
    }
    public boolean onTouchEvent(MotionEvent event)
    {
        synchronized (sync) {
            for(AControl item :this.globalControls)
                item.onClick(event);
        }

        return true;
    }
    public void onDraw(Canvas canvas)
    {
        synchronized (sync) {   
        ArrayList<AControl> temp  = (ArrayList<AControl>) this.globalControls.clone();
            for(AControl item :temp)
                item.onDraw(canvas);
        }
    }

}

3 个答案:

答案 0 :(得分:2)

你在这里克隆了你的清单:

 public void onDraw(Canvas canvas)
    {
        synchronized (sync) {   
        ArrayList<AControl> temp  = (ArrayList<AControl>) this.globalControls.clone();
            for(AControl item :temp)
                item.onDraw(canvas);
        }
    }

但不是之前的方法:

  public boolean onTouchEvent(MotionEvent event)
    {
        synchronized (sync) {
            for(AControl item :this.globalControls)
                item.onClick(event);
        }

        return true;
    }

我会说这就是问题所在。但是你没有包含堆栈跟踪的事实使得它更难猜测。添加同步不会解决您的问题,因为问题在于您可能在遍历列表时修改列表。

答案 1 :(得分:1)

ConcurrentModificationException的意思是,在使用迭代器或增强的for循环遍历集合时,您尝试在集合中添加或删除元素。

例如

List<String> list = new ArrayList<String>();
list.add("some string");
for (String str : list) {
    list.remove(str); // will throw a ConcurrentModificationException
}

在你的代码中,似乎你在遍历列表时调用了你的globalControls列表中按钮的委托方法(即item.onClickitem.onDraw将调用你拥有的EventHandler我注意到你在列表上进行同步,这在这种情况下无法帮助你,因为它是访问列表的同一个线程。

正如Ravi之前提到的那样,是因为在迭代它(在onTouchEvent中)之前你没有复制你的List,而是抛出了ConcurrentModificationException。确保在迭代之前复制列表!

作为一个方面,你不应该只在最短的时间内同步。

而不是

synchronized (sync) {   
    ArrayList<AControl> temp  = (ArrayList<AControl>) this.globalControls.clone();
        for(AControl item :temp) {
            item.onDraw(canvas);
        }
}

你应该写

ArrayList<AControl> copy;
synchronized (sync) {   
    copy = (ArrayList<AControl>) globalControls.clone();
    // exit synchronised block as we no longer need to be synchronised 
    // as we have a copy of the list now
}

for(AControl item : copy) {
    item.onDraw(canvas);
}

答案 2 :(得分:0)

在迭代它时(从相同或来自另一个线程)

,您无法修改为集合

您需要复制迭代(new ArrayList<>(existingList))或使用CopyOnWriteArrayList