繁体   English   中英

仍然出现并发修改错误

[英]Still getting concurrent modification error

好的,因此我在尝试编辑数组中的特定对象时遇到了并发修改异常。 据我了解,当您尝试同时遍历数组时尝试编辑数组时,会发生这种情况。 我尝试使用迭代器并同步访问数组的所有内容,但是没有运气。 经过一些研究,我发现有些人只是将值传递给另一个数组以编辑第一个数组(我知道这很令人困惑)。 所以我所做的只是我的代码现在看起来像

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;

    }

问题是我仍然遇到同样的错误! 但是,一旦我注释掉敌人列表.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)

有趣的是,我似乎还记得几天前看到的这段代码。 :)

我相信您正在允许其他线程在列表上进行迭代,而您的主线程正在从列表中删除元素。

看看这个:

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;
    }
});

这允许另一个线程遍历列表。

MyView还可以在另一个线程( implements Runnable )上运行,并且也可以foreach列表。

您想要的是某种线程安全列表。 看一下CopyOnWriteArrayList ,我认为它将解决您的问题。 使用列表提供的迭代器对其进行迭代。

从列表中删除时尝试使用synchronized

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM