2014-01-20 15 views
1

У меня есть класс Handler, который используется для рисования ArrayList башен в классе Gameviewандроид получаю сообщение об ошибке при попытке нарисовать на холсте

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

и, наконец, MainActivity, который реализует ontouchlistesnser

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 я получаю ошибку в методе жки обработчика

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) 

плз любую помощь?

+0

Что должны делать строки в ошибке в ваших классах? – Prmths

ответ

2

Проблема заключается в том, что вы добавляете в ArrayList, находясь в середине итерации по нему методом draw(). Вы не можете изменять коллекцию во время ее итерации (кроме удаления элементов с помощью Iterator).

Вы не показываете, что делает метод 'gameview.handle_imageView_TouchEvent()', но я думаю, вам нужно добавить его в ArrayList, используя тот же обработчик, который делает draw() и update(). Затем два процесса должны стоять в очереди в одном потоке и не сталкиваться.

+0

Thx очень, я не думал об этом, я добавил метод в обработчик для добавления нового объекта, и он отлично работает – user2625304

Смежные вопросы