2014-01-29 40 views
1

好吧,所以我一直在試圖編輯數組中的特定對象時得到併發修改異常。根據我的理解,當您嘗試在同時遍歷數組的同時編輯數組時,會發生這種情況。我嘗試使用迭代器並同步訪問數組的所有內容,但沒有運氣。經過一番研究後,我發現有些人只是將值傳遞給另一個數組,以便編輯第一個數組(我知道它很混亂)。所以我只是說我的代碼現在看起來像仍然有併發修改錯誤

public static void checkECount(int id) { 
     canUpdate = false; 
     enemiesList.remove(id); 
     enemyCount = enemyCount - 1; 

     ArrayList<Integer> arCount = new ArrayList<Integer>(); 
     int index = 0; 

     for(Sprite s : enemiesList) { 
       arCount.add(index); 
       index++; 
      } 
     for(Integer i : arCount){ 
      Sprite ss = enemiesList.get(i); 
      ss.setID(i); 
      } 

     arCount.clear(); 
     canUpdate = true; 

    } 

問題是我仍然得到相同的錯誤!但是,一旦我註釋掉enemiesList.remove(id);行它工作正常(以及它不做我想要的,但它不會再拋出錯誤)。有誰知道這裏發生了什麼?我將在底部添加其餘的代碼和logcat以防萬一需要它們。如果可以的話,請幫助,這個錯誤正在變成我瘋狂存在的禍根。

package com.gametest; 

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 
import android.app.Activity; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.os.Bundle; 
import android.view.MotionEvent; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.view.View.OnTouchListener; 

public class GameSurfaceView extends Activity implements OnTouchListener { 

    double ran; 
    int touchX, touchY, screenWidth, screenHeight, objX, objY; 
    static boolean canUpdate; 
    static int enemyCount; 
    static MyView v; 
    static Bitmap orb, explosion; 
    static List<Sprite> enemiesList = new ArrayList<Sprite>(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     v = new MyView(this); 
     v.setOnTouchListener(new OnTouchListener() { 

      @Override 
      public boolean onTouch(View v, MotionEvent me) { 
       touchX = (int) me.getX(); 
       touchY = (int) me.getY(); 
       for (Sprite sprite : enemiesList) { 
        sprite.checkTouch(touchX, touchY); 
       } 

       return true; 
      } 
     }); 
     canUpdate = true; 
     ran = 0; 
     orb = BitmapFactory.decodeResource(getResources(), R.drawable.blue_orb); 
     explosion = BitmapFactory.decodeResource(getResources(), R.drawable.explosion); 
     createEnemies(); 
     setContentView(v); 
    } 



    private void createEnemies() { 
     if (enemyCount < 5) { 
      screenWidth = v.getWidth(); 
      screenHeight = v.getHeight(); 
      int listLength = enemiesList.size(); 
      enemiesList.add(new Sprite(v, orb, explosion, screenWidth, screenHeight, listLength)); 
      enemyCount = enemyCount + 1; 
     } 
    } 

    public static void checkECount(int id) { 
     canUpdate = false; 
     enemiesList.remove(id); 
     enemyCount = enemyCount - 1; 

     ArrayList<Integer> arCount = new ArrayList<Integer>(); 
     int index = 0; 

     for(Sprite s : enemiesList) { 
       arCount.add(index); 
       index++; 
      } 
     for(Integer i : arCount){ 
      Sprite ss = enemiesList.get(i); 
      ss.setID(i); 
      } 

     arCount.clear(); 
     canUpdate = true; 

    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     v.pause(); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     v.resume(); 
    } 

    public class MyView extends SurfaceView implements Runnable { 

     Thread t = null; 
     SurfaceHolder holder; 
     boolean isItOk = false; 

     public MyView(Context context) { 
      super(context); 
      holder = getHolder(); 

     } 

     @Override 
     public void run() { 
      while (isItOk == true) { 
       if (!holder.getSurface().isValid()) { 
        continue; 
       } 
       Canvas c = holder.lockCanvas(); 
        if(canUpdate){ 
         canvas_draw(c); 
        } 
       holder.unlockCanvasAndPost(c); 

      } 

     } 

     protected void canvas_draw(Canvas canvas) { 
      canvas.drawARGB(255, 50, 10, 10); 
      String ranString = Integer.toString(screenHeight); 
      ran = Math.random() * 5; 
      if (ran > 3) { 
       createEnemies(); 
      } 

      Paint paint = new Paint(); 
      paint.setColor(Color.BLACK); 
      paint.setTextSize(15); 
      canvas.drawText(ranString, 10, screenHeight - 25, paint); 
      for (Sprite sprite : enemiesList) { 
       sprite.sprite_draw(canvas); 
      } 
     } 

     public void pause() { 
      isItOk = false; 
      while (true) { 
       try { 
        t.join(); 
       } catch (InterruptedException e) { 

       } 
       break; 
      } 
      t = null; 
     } 

     public void resume() { 
      isItOk = true; 
      t = new Thread(this); 
      t.start(); 
     } 

    } 

    @Override 
    public boolean onTouch(View arg0, MotionEvent arg1) { 
     // TODO Auto-generated method stub 
     return false; 
    } 

} 

而且繼承人的logcat的

01-29 21:58:51.140: E/AndroidRuntime(1135): FATAL EXCEPTION: main 
01-29 21:58:51.140: E/AndroidRuntime(1135): java.util.ConcurrentModificationException 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.gametest.GameSurfaceView$1.onTouch(GameSurfaceView.java:41) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.View.dispatchTouchEvent(View.java:7122) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1925) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1379) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.app.Activity.dispatchTouchEvent(Activity.java:2396) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1873) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.View.dispatchPointerEvent(View.java:7307) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3172) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3117) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4153) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4132) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4224) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.os.MessageQueue.nativePollOnce(Native Method) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.os.MessageQueue.next(MessageQueue.java:125) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.os.Looper.loop(Looper.java:124) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at android.app.ActivityThread.main(ActivityThread.java:4745) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at java.lang.reflect.Method.invokeNative(Native Method) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at java.lang.reflect.Method.invoke(Method.java:511) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
01-29 21:58:51.140: E/AndroidRuntime(1135):  at dalvik.system.NativeStart.main(Native Method) 
+1

你使用多個線程?如果是這樣的文檔說_it通常不允許一個線程修改一個集合,而另一個線程迭代它_ – csmckelvey

+0

除非我打開一些我不知道的線程。但我很確定它只是一個。 –

+1

我看到Runnables和't = new Thread(this); t.start();'這意味着你正在使用多個線程。這是除了首先運行你的應用程序的那個。 – csmckelvey

回答

0

有趣的消除,我似乎記得前幾天看到了這個代碼。 :)

我相信你是允許其他線程遍歷列表,而你的主線程是從它刪除元素威利尼利。

看看這個:

v.setOnTouchListener(new OnTouchListener() { 

    @Override 
    public boolean onTouch(View v, MotionEvent me) { 
     touchX = (int) me.getX(); 
     touchY = (int) me.getY(); 
     for (Sprite sprite : enemiesList) { 
      sprite.checkTouch(touchX, touchY); 
     } 
     return true; 
    } 
}); 

這allowes另一個線程來遍歷列表。

MyView也運行在另一個線程上,(implements Runnable),它也是foreach es在列表上。

你想要的是某種線程安全列表。看看CopyOnWriteArrayList,我認爲它會解決你的問題。使用列表提供的迭代器迭代它。

+0

非常感謝你,我很肯定這個工作。這一直困擾着我幾天,現在我非常激動地繼續前進。你是一個怪胎冠軍! –

-1

嘗試使用​​而從列表

synchronized(this){ 
    enemiesList.remove(id); 
} 
+0

真的有用嗎?它確保你不能同時調用remove(),但它沒有提到其他線程在foreach上迭代列表。 –

+0

它爲什麼要幫忙?這只是enemiesList被修改的許多地方之一。其他示例是 enemiesList.add(新的Sprite(v,orb,explosion,screenWidth,screenHeight,listLength)); –