2015-07-19 108 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。 –