android在尝试绘制到画布时出错

时间:2014-01-20 18:50:35

标签: java android arraylist

我有一个类Handler,用于在gameview类中绘制塔的arraylist

   public class Handler {
public static int Scale=50;
 public static ArrayList<Tower> towers=new ArrayList<Tower>();


public static void draw(Canvas c){
for(Tower t:towers){
    t.draw(c);
}
 }


public static void update(){
for(Tower t:towers){
    t.update();
}
 }

      }

GameView类,用于扩展surfaceview和implments surfaceholder.callback

           public class GameView  extends SurfaceView implements
           SurfaceHolder.Callback {

          public int ScreenWidth,ScreenHeight;

    TouchInput touchinput;
    TableLayout table;

    ///////////////////////////////////////
    //these variables used for adding new tower
    boolean addingnewtower=false;
    Bitmap Tempbitmap;
    public float x,y;
    //////////////////////////////////////
    public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    table=(TableLayout) findViewById(R.id.tablelayout1);
    Sprite sprite=new Sprite(context.getResources());

    touchinput=new TouchInput(this); 
    Tempbitmap=sprite.bitmap;
    // adding the callback (this) to the surface holder to intercept events
    getHolder().addCallback(this);
            setFocusable(true);//
}

    private static final String TAG = GameView.class.getSimpleName();

    private MainThread thread;




    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    // at this point the surface is created and
    // we can safely start the game loop
//if(!thread.isAlive()){
setOnTouchListener(touchinput);
    thread = new MainThread(getHolder(), this);
    thread.setRunning(true);
    thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
            Log.d(TAG, "Surface is being destroyed");
    // tell the thread to shut down and wait for it to finish
    // this is a clean shutdown
            boolean retry = true;
    thread.setRunning(false);
    while (retry) {
try {
    thread.join();
    retry = false;
} catch (InterruptedException e) {
    // try again shutting down the thread
}
    }
    Log.d(TAG, "Thread was shut down cleanly");

    }




    public void Draw(Canvas c) {
Paint paint=new Paint();//paint used to set color,text font,text size...
paint.setColor(Color.RED);
paint.setTextSize(paint.getTextSize()*3);
c.drawRect(100,100,200,200,paint);
c.drawText("touch is"  +  x   +  "  "+  y,200,200, paint);

Handler.draw(c);
if(addingnewtower){
    c.drawBitmap(Tempbitmap,x,y, paint);
}

    }  

    public void update(){

Handler.update();
    }

类mainthread,它包含方法run()

中的游戏循环
   public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();

// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private GameView gameview;

// flag to hold game state 
private boolean running;
public void setRunning(boolean running) {
    this.running = running;
}

public MainThread(SurfaceHolder surfaceHolder,GameView gameview) {
    super();
    this.surfaceHolder = surfaceHolder;
    this.gameview = gameview;
}

@Override
public void run() {
    Canvas canvas;
    Log.d(TAG, "Starting game loop");
    while (running) {
        canvas = null;
        // try locking the canvas for exclusive pixel editing on the surface
        try {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) {

                if(canvas!=null){
                    canvas.drawColor(Color.BLACK);
                gameview.Draw(canvas);}
                gameview.update();
            }
        } finally {
            // in case of an exception the surface is not left in 
            if (canvas != null) {
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }   // end finally
    } 
}
 }

最后是实现ontouchlistesnser的MainActivity

public class MainActivity extends Activity implements OnTouchListener  {
             private ImageView tower1,tower2,tower3,tower4,tower5,tower6;
  private TableLayout layout;
   private GameView gameview;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
     requestWindowFeature(Window.FEATURE_NO_TITLE);//hide the action bar

             getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//make it full screen

    setContentView(R.layout.activity_main);
    gameview=(GameView) findViewById(R.id.gameview1);
    tower1=(ImageView) findViewById(R.id.tower1);
    layout=(TableLayout) findViewById(R.id.tablelayout1);
    tower1.setOnTouchListener(this);
    gameview.setOnTouchListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    gameview.onpause();
}

@Override
protected void onResume() {
    super.onResume();
    gameview.onresume();
}



//this is called whenever an imageview is touched for adding a new tower on the map
@Override
public boolean onTouch(View v, MotionEvent m) {
    int location[]=new int[2];
    tower1.getLocationOnScreen(location);//get the location of imageview with respect to screen since the touch area will be with respect to the view v width and height
    switch(m.getAction()){
    case MotionEvent.ACTION_DOWN:
    if(v.getId()==tower1.getId()){//if tower1 is touched
        layout.setVisibility(View.INVISIBLE);//make them invisible
        }
    break;
    case MotionEvent.ACTION_MOVE:

    gameview.handle_imageView_TouchEvent(location,m.getX(),m.getY(),false);//false meaning in touch move

    break;
    case MotionEvent.ACTION_UP:
        gameview.handle_imageView_TouchEvent(location,m.getX(),m.getY(),true);//this will be called only once for adding the new tower 
layout.setVisibility(View.VISIBLE);
gameview.addingnewtower=false;
    break;

    }
    return true;

}


  }

当这个代码做的时候,每当我触摸一个imageview并将它拖过屏幕时,一个新的对象机器人将延伸塔添加到处理程序类的arraylist塔中 但是几次将新的机器人添加到arraylist后我在处理程序的draw方法中出现错误

 01-20 18:16:13.261: E/AndroidRuntime(1339): FATAL EXCEPTION: Thread-114
 01-20 18:16:13.261: E/AndroidRuntime(1339): java.util.ConcurrentModificationException
 01-20 18:16:13.261: E/AndroidRuntime(1339): at  java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)               
01-20 18:16:13.261: E/AndroidRuntime(1339):     at com.example.test1.Handler.draw(Handler.java:15)
01-20 18:16:13.261: E/AndroidRuntime(1339):     at com.example.test1.GameView.Draw(GameView.java:97)
01-20 18:16:13.261: E/AndroidRuntime(1339):     at com.example.test1.MainThread.run(MainThread.java:44)

是否有任何帮助?

1 个答案:

答案 0 :(得分:2)

问题似乎是你在使用draw()方法迭代它的同时添加到ArrayList。迭代时不能修改集合(除了使用迭代器删除项目)。

你没有显示'gameview.handle_imageView_TouchEvent()'的方法,但我认为你需要使用与draw()和update()相同的Handler来添加到ArrayList。然后,这两个进程应该在同一个线程上排队,不会发生冲突。