迭代Hashmap会导致崩溃

时间:2015-02-24 16:16:31

标签: java android

我注意到我的应用程序最近崩溃了很多,经过调试后我发现当我迭代哈希映射时,有些会随机崩溃。

我像那样迭代他们:

for (Map.Entry<Point, Particle> entry : spawned.entrySet()) {
                entry.getValue().Draw(canvas);
        } 

导致: enter image description here

之后我尝试使用迭代器迭代它们:

        Iterator<Map.Entry<Point, Particle>> entries = spawned.entrySet().iterator();
    while (entries.hasNext()) {
        Map.Entry<Point, Particle> entry = entries.next();
        entry.getValue().Draw(canvas);
    }

但是这导致了: enter image description here

这里面是粒子类,如果有人怀疑它必须对它做一些事情:

public class Particle {
    Bitmap bit;
    int alpha = 0;
    boolean appeared = false;
    boolean dissapiread = false;
    int time = 1;
    PointF position;
    Handler handler;
    int counter = 0;
    PointF newpose;
    float newsize=0;
    int timer2=0;
    public Particle(Bitmap b, PointF p, int time) {
        int rand=(randInt(-b.getWidth()/2, b.getWidth()));
        this.bit = Bitmap.createScaledBitmap(b, b.getWidth()+rand,b.getHeight()+rand,false);
        this.position = p;
        this.time = time;
        newpose= new PointF();
        newpose.x=p.x+randInt(-15000, 15000);
        newpose.y=p.y+randInt(-15000,15000);

    }

    public void Draw(Canvas c) {
        update();
        Paint paintAlpha = new Paint();
        paintAlpha.setAlpha(alpha);
        c.drawBitmap(bit, position.x, position.y, paintAlpha);
    }
    public static int randInt(int min, int max) {
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }
    private void update() {
        if(position.x<newpose.x){
            position.x+=0.10f;
        }
         if(position.x>newpose.x){
            position.x-=0.10f;
        }
        if(position.y<newpose.y){
            position.y+=0.10f;
        }
         if(position.y>newpose.y){
            position.y-=0.10f;
        }
         if(dissapiread==false){
         if(timer2==0){
             newsize+=0.10;
             try {
                 bit=Bitmap.createScaledBitmap(bit, bit.getWidth()-(int)newsize,bit.getHeight()-(int)newsize,false);
            } catch (Exception e) {
                // TODO: handle exception
            }
         timer2=5;
         }
         else
             timer2--;
         }

        if (appeared == false) {
            if (alpha <=240) {
                alpha =alpha+10;
            } 
            else {
                if(counter==0){

                counter=time;
                }
                if(counter==1){
                    appeared=true;
                }
                else
                    counter--;
            }
        } else {
            if (dissapiread == false) {
                if (alpha != 0) {
                    alpha=alpha-10;
                }
                else
                    dissapiread = true;
            }
        }
    }
}

请注意,我知道在我目前的代码中我不必使用散列图,我只是想了解它崩溃的原因,因为它也发生在其他地方。

编辑: 整个代码:

public class gameview extends SurfaceView {

    private GameLoopThread gameLoopThread;
    private SurfaceHolder holder;
    Bitmap partic;
    Particle pp;
    Map<Point, Particle> spawned = new HashMap<Point, Particle>();
public gameview(Context c) {
    super(c);
    partic=BitmapFactory.decodeResource(getResources(),
            R.drawable.particle_fire);
     pp=new Particle(partic, new PointF(0,0), 100);
    gameLoopThread = new GameLoopThread(this);
    this.requestFocus();
    this.setFocusableInTouchMode(true);
    holder = getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            gameLoopThread.setRunning(false);
            while (retry) {
                try {
                    gameLoopThread.join();
                    retry = false;
                } catch (InterruptedException e) {
                }
            }
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            gameLoopThread.setRunning(true);
            gameLoopThread.start();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format,
                int width, int height) {
        }
    });
}
@Override
public void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    canvas.drawColor(Color.BLACK);
    pp.Draw(canvas);
        Iterator<Map.Entry<Point, Particle>> entries = spawned.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<Point, Particle> entry = entries.next();
            entry.getValue().Draw(canvas);
        }
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = (float) (event.getX());
    float y = (float) (event.getY());
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        spawned.put(new Point((int)x,(int)y), new Particle(partic, new PointF(x,y), 100));
        break;
    }
    return super.onTouchEvent(event);
}
private void newParticle(int x,int y){

    spawned.put(new Point(0,0), new Particle(partic, new PointF(x,y), 100));
}

}

1 个答案:

答案 0 :(得分:0)

您在Partice方法中更新了Draw。这导致你在循环中遇到ConcurrentModificationException

如果要避免这种异常,可以创建一个“粒子集合”的克隆,通过该克隆迭代并修改原始数据。但是,克隆对于您需要做的事情来说可能非常麻烦。

使用克隆我的意思是将HashMap的键复制到一个新的Set中并迭代该集合。在循环中,您可以通过迭代的键访问HashMap值。修改粒子应该没问题。请注意,如果更新更改了对象的HashValue,则需要小心。

修改

正如@fge指出的那样,使用CuncurrentHashMap也可以解决问题。