处理TouchEvents concurrentModificationException android

时间:2015-07-19 17:41:26

标签: java android canvas ontouchevent

我试图在SurfaceView类中使用画布在screeen上绘制一些气球,我成功地能够在画布上绘制多个气球并通过交换不同的图像来动画它们。问题是当我尝试触摸Oneballoon时,我需要将其从屏幕上删除。这是我得到这个例外而且我被卡住了

代码: MainActivity:

textColor

}

GameView.java

function getCurrentBetInformations () {
connection.query('SELECT * FROM `BETS` WHERE BET_ACTIVE = "1" LIMIT 1', function(err, rowss, fields) {

    if (err) logger.warn('MySQL Error: ' + err.stack);

    betid   = rowss[0].BET_ID;
    betends = rowss[0].BET_END;
    connection.query('SELECT * FROM `BETS_BID` WHERE BID_BET_ID=\'' + betid + '\'', function(err, betbids, fields) {

        if (err) logger.warn('MySQL Error: ' + err.stack);

        var betQuants       = new Array();
        var betIds          = new Array();
        var betUsernames    = new Array();
        var betDates        = new Array();
        var rowsAffected    = betbids.length;

        for(i=0; i < rowsAffected; i++) {
            betQuants.push(betbids[i].BID_KEYS_COUNT);
            betIds.push(betbids[i].BID_ID);
            var betSender = betbids[i].BID_SENDER;
            connection.query('SELECT `USER_NAME` FROM `USER` WHERE `USER_STEAMID` = \'' + betSender + '\' LIMIT 1', function(err, rows, fields) {
                if (err) logger.warn('MySQL Error: ' + err.stack);

                console.log(rows[0].USER_NAME);
                addUsername(rows[0].USER_NAME);
            });
            function addUsername (currentUsername) {
                betUsernames.push(currentUsername);
            }
            betDates.push(betbids[i].BID_TIME);
            if(betUsernames.length === i) {
                execSiteRef();
            }
        }
        function execSiteRef() {
            console.log(betUsernames);
            sendUserSiteRefresh([betQuants, betIds, betUsernames, betDates], betends);
        }
    }); 
}); 

GameLoopThread.java

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 */
}

Balloon.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;
}
}

我很困惑,为什么它会导致这样的错误,任何人都可以看看它并建议我一个解决方案,这是正确的删除方法吗?

请分享任何建议

由于

3 个答案:

答案 0 :(得分:1)

删除错误的方法。

如果迭代Collection / List,并想要删除当前元素,则必须使用Iterator.remove()方法。

在您的情况下,只需致电balloonIterator.remove()而不是balloons.remove(0)

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

答案 1 :(得分:0)

此异常是由于同时修改了列表气球。

一旦你触摸表面视图onDraw()就会被onTouch()调用,你正在处理列表气球。

我认为你应该为气球而不是GameView添加触控监听器。

答案 2 :(得分:0)

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

Try...