Java 处理TouchEvents concurrentModificationException android

Java 处理TouchEvents concurrentModificationException android,java,android,canvas,touch-event,Java,Android,Canvas,Touch Event,我试图在SurfaceView类中使用画布在screeen上绘制一些气球,我成功地在画布上绘制了多个气球,并通过交换不同的图像来设置它们的动画。问题是当我尝试触摸一个气球时,我需要将它从屏幕上移除。在这里,我遇到了这个异常,我被卡住了 代码: 主要活动: package com.pradhul.game.touchball; import android.app.Activity; import android.os.Bundle; public class MainActivity exte

我试图在SurfaceView类中使用画布在screeen上绘制一些气球,我成功地在画布上绘制了多个气球,并通过交换不同的图像来设置它们的动画。问题是当我尝试触摸一个气球时,我需要将它从屏幕上移除。在这里,我遇到了这个异常,我被卡住了

代码: 主要活动:

package com.pradhul.game.touchball;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new GameView(this));
    /*TODO Hide the bottom navigation bar */
}
}

GameView.java

package com.pradhul.game.touchball;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GameView extends SurfaceView implements    SurfaceHolder.Callback, View.OnTouchListener {
private static final int NUM_OF_BALLOONS = 5; //TODO for more than one  balloons animations dont work(?)
/*use SurfaceView because we want complete control over the screen.
    * unlike extending View class the oDraw() Method will not be called automatically
    * from the method onSurfaceCreated() we have to call it Manually and pass a canvas object into it
    * */
private final SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Balloon> balloons =  new ArrayList<>();

public GameView(Context context) {
    super(context);
    gameLoopThread = new GameLoopThread(this);
    holder = getHolder();
    holder.addCallback(this);
    createBalloons(NUM_OF_BALLOONS);
    this.setOnTouchListener(this);
}

private void createBalloons(int count) {
    for(int i=0 ; i< count ;i++){
        balloons.add(createBalloon());
    }
}

@Override
protected void onDraw(Canvas canvas) {
    if(canvas != null) {
        canvas.drawColor(Color.WHITE);
        for(Balloon balloon : balloons){
            try {
                gameLoopThread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            balloon.onDraw(canvas);
        }
    }
}

@SuppressLint("WrongCall")
@Override
public void surfaceCreated(SurfaceHolder holder) {
    /*this is called when the view is created*/
    gameLoopThread.setRunning(true);
    gameLoopThread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    /*pausing game Thread*/
    gameLoopThread.setRunning(false);
    while (true){
        try {
            gameLoopThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
private  Balloon createBalloon(){
    return new Balloon(this);
}


@Override
public synchronized boolean onTouch(View v, MotionEvent event) {
    Log.d("OnTouch real -", "x: " + event.getX() + ", Y: " + event.getY());
 /*   for (int i = balloons.size()-1; i >= 0; i--) {
        Balloon balloon = balloons.get(i);
        Log.d("OnTouch collision -", !balloon.isCollision(event.getX(), event.getY())+"");
        if (!balloon.isCollision(event.getX(), event.getY())) {
            balloons.remove(0);
            break;
        }
    }*/
    Iterator<Balloon>  balloonIterator = balloons.iterator();
    while(balloonIterator.hasNext()){
        Balloon balloon = balloonIterator.next();
        balloons.remove(0);
    }
    return true;
}
}
Balloon.java

package com.pradhul.game.touchball;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import java.util.Random;

public class Balloon {
private static final int BALLOON_SPEED = 10;
private int y = 0;
private int x = 0;
private int speed = 1;
private GameView gameView;
private Bitmap balloon;
public Bitmap[] normalBalloons;
private int balloonIndex = 0;

private int normalImages[] = {R.drawable.normal_01,R.drawable.normal_02,R.drawable.normal_03,
        R.drawable.normal_04,R.drawable.normal_05,R.drawable.normal_06,R.drawable.normal_07,
        R.drawable.normal_08,
};
private int crackingImages[] = {R.drawable.crack_01,R.drawable.crack_02,R.drawable.crack_03,
        R.drawable.crack_04, R.drawable.crack_05,R.drawable.crack_04,R.drawable.crack_03,
        R.drawable.crack_02
};
private boolean reverseSwap = false;


public Balloon(GameView gameView){
    this.gameView = gameView;
    normalBalloons = new Bitmap[8];
    setUpImages();
}

public  void onDraw(Canvas canvas){
    /*draws the balloon in canvas */
    animateBalloon();
    update(canvas.getWidth());
    canvas.drawBitmap(balloon, x, y, null);
}

public boolean isCollision(float x2, float y2) {
    return x2 > x && x2 < x + balloon.getWidth() && y2 > y && y2 < y + balloon.getHeight();
}

private int getRandomX(int maxVal) {
    Random rand = new Random();
    return rand.nextInt(maxVal);
}

private void animateBalloon() {
    /*Animates the balloon by swapping resource image at each call*/
    this.balloon = getBalloons();
    Log.d("Balloon",balloonIndex % normalBalloons.length + "");
}

private void update(int canvasWidth) {
    /*updates the y position for moving the balloon*/
    if (y <= 0){
        /*so that the balloon starts from bottom
        * gameView will return a height only after the View is ready
        * getting 0 in constructor of this class*/
        y = gameView.getHeight();
        /*x is assigned a random between the width od the canvas
        * so that the balloons will appear random positions from below*/
        x = getRandomX(canvasWidth - balloon.getWidth());
    }
    if (y > gameView.getHeight() - balloon.getHeight() - speed) {
        speed = -BALLOON_SPEED;
    }
    y = y + speed;
    Log.d("Balloon","Positions:"+x+","+y);
}

private Bitmap getBalloons() {
    if(balloonIndex == normalBalloons.length-1) {
        reverseSwap = true;
    }
    if(balloonIndex == 0){
        reverseSwap = false;
    }
    balloonIndex = reverseSwap?balloonIndex-1:balloonIndex+1;
    return normalBalloons[balloonIndex];
}

private void setUpImages() {
    /*setting up resources array*/
    for(int count =0; count < normalImages.length; count++){
        Bitmap balloon =   BitmapFactory.decodeResource(gameView.getResources(), normalImages[count]);
        normalBalloons[count] = balloon;
    }


}
}
package com.pradhul.game.touchball;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.graphics.Canvas;
导入android.util.Log;
导入java.util.Random;
公营气球{
专用静态最终int气球_速度=10;
私有整数y=0;
私有整数x=0;
私人整数速度=1;
私人游戏视图游戏视图;
私人位图气球;
公共气球;
私有索引=0;
私有int normalImages[]={R.drawable.normal_01,R.drawable.normal_02,R.drawable.normal_03,
可拉深,正常04,可拉深,正常05,可拉深,正常06,可拉深,正常07,
R.drawable.normal_08,
};
private int crackingImages[]={R.drawable.crack_01,R.drawable.crack_02,R.drawable.crack_03,
R.drawable.crack_04,R.drawable.crack_05,R.drawable.crack_04,R.drawable.crack_03,
R.可拉深的裂纹\u 02
};
私有布尔反转wap=false;
公共气球(GameView GameView){
this.gameView=gameView;
NormalBallobs=新位图[8];
设置图像();
}
公共空白onDraw(画布){
/*在画布中绘制气球*/
animateBalloon();
更新(canvas.getWidth());
drawBitmap(气球、x、y、空);
}
公共布尔值isCollision(浮点x2,浮点y2){
返回x2>x&&x2y&&y2
我很困惑,为什么它会导致这样的错误,任何人都可以看看它,并建议我一个解决方案,这是正确的方式来消除

请分享任何建议


谢谢

此异常是由于同时修改列表引出序号造成的

一旦您接触到曲面视图,onDraw()就会被onTouch()调用,在onTouch()中,您正在处理列表引出序号


我认为您应该将触控监听器添加到balloon,而不是GameView。

删除触控监听器的方法是错误的

如果对集合/列表进行迭代,并希望删除当前元素,则必须使用Iterator.remove()方法

在您的情况下,只需调用
ballodeIterator.remove()
而不是
ballods.remove(0)

更简单的是,因为您希望从列表中删除所有元素-您只需调用
ballogs.clear()
并完全删除循环。

好的, 我需要将我所有的代码包装在一个同步的持有者中,这样才能工作 (不太了解)

@覆盖
公共布尔onTouch(视图v,运动事件){
Log.d(“OnTouch”,“x:+event.getX()+”Y:+event.getY());
已同步(getHolder()){

对于(int i=0;iBut OnTouchListener接口与View类关联,我如何在自定义类中输入该接口?我认为GameView类扩展了surfaceView,因此视图应该考虑触摸,我无法在我的类中调用setOnTouchListner也看看这个问题-谢谢,但在这种情况下,我得到了一个n IlligalstateException.synchronized语句make确保线程安全,这意味着变量不会被不同的线程随机触及,因为它们可能在不同的/并发的时间触发/完成
package com.pradhul.game.touchball;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import java.util.Random;

public class Balloon {
private static final int BALLOON_SPEED = 10;
private int y = 0;
private int x = 0;
private int speed = 1;
private GameView gameView;
private Bitmap balloon;
public Bitmap[] normalBalloons;
private int balloonIndex = 0;

private int normalImages[] = {R.drawable.normal_01,R.drawable.normal_02,R.drawable.normal_03,
        R.drawable.normal_04,R.drawable.normal_05,R.drawable.normal_06,R.drawable.normal_07,
        R.drawable.normal_08,
};
private int crackingImages[] = {R.drawable.crack_01,R.drawable.crack_02,R.drawable.crack_03,
        R.drawable.crack_04, R.drawable.crack_05,R.drawable.crack_04,R.drawable.crack_03,
        R.drawable.crack_02
};
private boolean reverseSwap = false;


public Balloon(GameView gameView){
    this.gameView = gameView;
    normalBalloons = new Bitmap[8];
    setUpImages();
}

public  void onDraw(Canvas canvas){
    /*draws the balloon in canvas */
    animateBalloon();
    update(canvas.getWidth());
    canvas.drawBitmap(balloon, x, y, null);
}

public boolean isCollision(float x2, float y2) {
    return x2 > x && x2 < x + balloon.getWidth() && y2 > y && y2 < y + balloon.getHeight();
}

private int getRandomX(int maxVal) {
    Random rand = new Random();
    return rand.nextInt(maxVal);
}

private void animateBalloon() {
    /*Animates the balloon by swapping resource image at each call*/
    this.balloon = getBalloons();
    Log.d("Balloon",balloonIndex % normalBalloons.length + "");
}

private void update(int canvasWidth) {
    /*updates the y position for moving the balloon*/
    if (y <= 0){
        /*so that the balloon starts from bottom
        * gameView will return a height only after the View is ready
        * getting 0 in constructor of this class*/
        y = gameView.getHeight();
        /*x is assigned a random between the width od the canvas
        * so that the balloons will appear random positions from below*/
        x = getRandomX(canvasWidth - balloon.getWidth());
    }
    if (y > gameView.getHeight() - balloon.getHeight() - speed) {
        speed = -BALLOON_SPEED;
    }
    y = y + speed;
    Log.d("Balloon","Positions:"+x+","+y);
}

private Bitmap getBalloons() {
    if(balloonIndex == normalBalloons.length-1) {
        reverseSwap = true;
    }
    if(balloonIndex == 0){
        reverseSwap = false;
    }
    balloonIndex = reverseSwap?balloonIndex-1:balloonIndex+1;
    return normalBalloons[balloonIndex];
}

private void setUpImages() {
    /*setting up resources array*/
    for(int count =0; count < normalImages.length; count++){
        Bitmap balloon =   BitmapFactory.decodeResource(gameView.getResources(), normalImages[count]);
        normalBalloons[count] = balloon;
    }


}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
    Log.d("OnTouch","x:"+event.getX()+"Y:"+event.getY());
    synchronized (getHolder()){
        for (int i=0 ;i<balloons.size();i++){
            balloons.remove(0);
            break;
        }
    }
    return true;
}