2015-07-19 102 views
1

我试图在SurfaceView类中使用画布在screeen上绘制一些气球,我成功地在画布上绘制了多个气球,并通过交换不同的图像来为它们制作动画。问题是,当我尝试触及Oneballoon我需要从屏幕上删除它。在这里我得到这个例外,我坚持处理TouchEvents并发修复异常android

代码: MainActivity:

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

GameLoopThread.java

package com.pradhul.game.touchball; 
import android.annotation.SuppressLint; 
import android.graphics.Canvas; 

public class GameLoopThread extends Thread { 

private GameView view; 
private boolean running = false; 

public GameLoopThread(GameView view){ 
    this.view = view; 
} 
public void setRunning(boolean run){ 
    running = run; 
} 

@SuppressLint("WrongCall") 
public void run(){ 
    while (running){ 
     Canvas canvas = null; 
     try{ 
      canvas = view.getHolder().lockCanvas(); 
      synchronized (view.getHolder()){ 
       view.onDraw(canvas); 
      } 
     }finally{ 
      if(canvas != null) { 
       view.getHolder().unlockCanvasAndPost(canvas); 
      } 
     } 
    } 

} 
} 

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


} 
} 

我感到困惑的是,为什么它会导致这样的错误,可有人可以看看它,并建议我一个解决方案,这是改掉正确的方法是什么?

请分享任何建议

感谢

回答

0

没关系,我 需要包装序此同步架在我的所有代码工作 (不很了解)

@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; 
} 
+1

synchronized语句确保线程安全,这意味着变量不会被不同的线程随机触及,因为它们可能在不同/同时发生/完成 – kimchibooty

0

这个异常是由于列表气球的并发修改。

只要触摸表面视图onDraw()就会被onTouch()调用,其中您正在使用列表气球。

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

+0

但OnTouchListener接口被关联到视图类,我怎么能在我的自定义类中实现?我在考虑GameView类扩展了SurfaceView,所以视图应该保持接触,我无法在我的类中调用setOnTouchListner –

1

这是删除的错误方法。

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

在你的情况,只需拨打的balloonIterator.remove()代替balloons.remove(0)

就更简单了,因为你想从列表中删除的所有元素 - 你应该简单地调用balloons.clear()和完全删除循环。

+0

也看看这个问题 - http://stackoverflow.com/questions/ 223918/iterating-through-a-list-avoid-concurrentmodificationexception-when-removal –

+0

谢谢,但在这种情况下,我得到一个IlligalstateException。 –