2011-11-18 70 views
0

我花了整整一天試圖解決這個問題。我嘗試使用itertaion?同步和其他許多薩滿法,但是我一直在得到ConcurrentModificationException。這裏是代碼。ConcurrentModificationException當我試圖將項目添加到集合

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

不能修改的集合,而迭代它(從相同或從另一個線程)

要麼你需要做的是你迭代副本(new ArrayList<>(existingList)),或使用CopyOnWriteArrayList

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

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將調用事件處理程序你我注意到你在同步列表中,這在這種情況下不會幫助你,因爲它是訪問列表的同一線程

由於Ravi之前提到過,這是因爲你不會複製你的在迭代之前列出它(在onTouchEvent) 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); 
}