我花了一整天时间试图解决这个问题。我尝试使用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);
}
}
}
答案 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.onClick
和item.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