Удалить элемент из ArrayList, исключение ArrayIndexOutOfBounds

#android #exception #thread-safety #arraylist

#Android #исключение #потокобезопасность #arraylist

Вопрос:

В настоящее время у меня есть arraylist, в который я добавляю объекты «blossom» (которые выпадают из верхней части экрана). Когда происходит столкновение между цветком и полем в нижней части экрана, я хочу удалить цветок из ArrayList. однако, то, как я делаю это сейчас (в классе blossom), я получаю исключение ArrayIndexOutOfBounds. Кто-нибудь может увидеть, где я ошибаюсь? Я знаю, что это связано с моими потоками, я просто не могу понять, КУДА поместить этот метод. (Это выполняется в методе «hit» моего класса Blossom).

BoardView

     public BoardView(Context context){
    super(context);

    scorePaint.setColor(Color.BLACK);
    scorePaint.setTextSize(12);
    scorePaint.setTypeface(Typeface.MONOSPACE);


    //surfaceHolder provides canvas that we draw on
    getHolder().addCallback(this);

    // controls drawings
    thread = new BoardThread(getHolder(),this, blossomArrayList, box_x, box_y, 
            boxWidth, boxHeight);

    timer = new Thread(){
        public void run(){
            //makes sure the player still has 3 lives left
            while(game == false){
                uiCallback.sendEmptyMessage(0);
                try {
                    Thread.sleep(2000); // wait two seconds before drawing the next flower
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } //sleep for 2 seconds
            }
        }
    };
    timer.start();

    //intercepts touch events
    setFocusable(true);

}

@Override

public void onDraw(Canvas canvas){
    canvas.drawColor(Color.WHITE);
    score = "SCORE: "   currentScore;

    //note: pay attention to order you draw things
    //don't change order or else blossoms will fall
    //on top of box, not "into" it.

    //display the scoreboard
    canvas.drawText(score,240,420,scorePaint);
    // uses a synchronized method to prevent concurrent modification
    DrawBlossoms(canvas);
    canvas.drawBitmap(box, box_x, box_y, null);

}

@Override
public boolean onTouchEvent(MotionEvent event){
    //handles movement of box
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        if(event.getX() > box_x amp; event.getY() > box_y amp; 
                event.getX() < box_x   boxWidth amp; event.getY() < box_y   boxHeight)
        {
            mode = true;
        }
    }

    if(event.getAction() == MotionEvent.ACTION_MOVE) {
        if(event.getX() > box_x amp; event.getY() > box_y amp; 
                event.getX() < box_x   boxWidth amp; event.getY() < box_y   boxHeight)
        {
            mode = true;
        }
        if(mode == true){
            box_x = (int)event.getX();
        }   

    }

    if(event.getAction() == MotionEvent.ACTION_UP){
        mode = false;
    }

    invalidate();
    return true;
}

@Override
public void surfaceChanged(SurfaceHolder holder, 
        int format, int width, int height ){
    Log.v(TAG, "Surface Changed");
    //somehow these don't seem to be working
}

@Override
public void surfaceCreated(SurfaceHolder holder){
    thread.startRunning(true);
    thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder){
    Log.v(TAG, "Surface Destroyed");
    //somehow these don't seem to be working
    thread.startRunning(false);
    thread.stop();
    timer.interrupt();
    timer.stop();
}

private Handler uiCallback = new Handler(){
    public synchronized void handleMessage(Message msg){
        //add a new blossom to the blossom ArrayList!!
        blossomArrayList.add(new Blossom( 
            (BitmapFactory.decodeResource
                    (getResources(), R.drawable.blossom))));
        blossomNum  ;

        //remove neccesary blossoms from list
        Log.v(TAG, "Number of Blossoms ="   blossomNum);
    }
};

private synchronized void DrawBlossoms(Canvas c)
{
    Canvas canvas = c;
    for(Blossom blossom: blossomArrayList)   // getting errors here
    {
            blossom.Draw(canvas);
            blossom.hit(box_x,box_y, box_x   boxWidth, box_y   boxHeight, blossomArrayList);

    }
}
  

}

Класс Blossom

 public Blossom(Bitmap bitmap)
{
    blossom = bitmap;
    blossomWidth = blossom.getWidth();
    blossomHeight = blossom.getHeight();
    blossom_x = generator.nextInt(320-blossom.getWidth());
    blossomRect = new RectF(blossom_x,blossom_y, blossom_x   blossomWidth, blossom_y   blossomHeight);
}

public Bitmap getBitmap()
{
    return blossom;
}

public Boolean hit(int boxLeft, int boxTop, int boxRight,int boxBottom, ArrayList<Blossom> blossomArrayList)
{
    if(remove == true)
    {
        Log.v(TAG, "Remove = true");
        blossomArrayList.remove(removeInt);
        remove = false;
    }
    if(blossom_x > boxLeft amp; blossom_y > boxTop
            amp; blossom_x   blossom.getWidth() < boxRight
            amp; blossom_y   blossom.getHeight() < boxBottom)
    {
        Log.v(TAG, "Collision Detected");
        remove = true;
        removeInt = blossomArrayList.indexOf(blossom);

        return true;
    }
    else
    {
        return false;
    }
}

public float getBlossomX()
{
    return blossom_x;
}

public float getBlossomY()
{
    return blossom_y;
}

public float getBlossomWidth()
{
    return blossomWidth;
}

public float getBlossomHeight()
{
    return blossomHeight;
}

public void Draw(Canvas canvas)
{
    //draws the flower falling
    if (hit == false)
    {
        canvas.drawBitmap(blossom, blossom_x,
            blossom_y = blossom_y 5 , null);
    }

}

public void UpdatePosition()
{
    blossomRect.set(blossom_x, blossom_y, blossom_x   25, blossom_y   25);
}
  

}

Поток платы

     public BoardThread(SurfaceHolder holder, BoardView boardView2, 
        ArrayList<Blossom> blossomArrayList1,
        int box_x, int box_y, int boxW, int boxH) {

    surfaceHolder = holder;
    boardView=boardView2;

    blossomArrayList = blossomArrayList1;
    boxX = box_x;
    boxY = box_y;
    boxW = boxWidth;
    boxH = boxHeight;
}

public void startRunning(boolean run) {

    mrun=run;
}

@Override
public void run() {

    super.run();
     Canvas canvas;
     while (mrun) {
        canvas=null;
         try {
             canvas = surfaceHolder.lockCanvas(null);
              synchronized (surfaceHolder) {
                 //update position
                 Position(blossomArrayList, boxX, boxY, boxWidth, boxHeight);
                 // draw flowers
                 boardView.onDraw(canvas);   // and getting errors here - concurrent 
             }
         } finally {
                 if (canvas != null) {
                 surfaceHolder.unlockCanvasAndPost(canvas);
             }
         }
     }
  }

private synchronized void Position(ArrayList<Blossom> blossomArrayList, int box_x, int box_y, 
        int boxWidth, int boxHeight)
{
    for(Blossom blossom: blossomArrayList)
    {
        blossom.UpdatePosition();
    }
}

}
  

Комментарии:

1. Покажите нам logcat, в какой строке находится ваш AIOOB?

2. Пожалуйста, не могли бы вы предоставить краткий тестовый пример с выводом ошибки.

3. Я получаю при ArrayList.java (408).

4. также в blossomarraylist.remove в классе blossom.

5. также в blossom.hit(box_x,box_y, box_x boxWidth, box_y boxHeight, blossomArrayList); в классе boardview.

Ответ №1:

Проблема в том, что вы предоставляете целое число в качестве параметра для метода remove, в то время как он рассматривает его как индекс ArrayList.

ArrayList предоставляет два метода, которые:

 public E remove(int index)
public boolean remove(Object o)
  

Что вы можете сделать, так это:
1) создайте ArrayList типа string.
2) преобразуйте ваш int в string и используйте его как-

 blossomArrayList.remove(String.valueOf(removeInt));
  

Надеюсь, это поможет..

Ответ №2:

Предполагая, что вы получаете ошибку при blossomArrayList.remove(removeInt); , вы могли бы попытаться удалить сам объект, поскольку .remove(..) он может принимать параметр объекта.

Комментарии:

1. Проблема в том, что это, вероятно, приведет к ошибке. поскольку он находится в цикле for each, если я попытаюсь удалить цветок, на который я смотрю, это, скорее всего, приведет к сбою.

2. На самом деле, вы могли бы просто сделать blossomArrayList.remove(this); , чтобы удалить текущий blossom. Он не выдаст ошибку, даже если он не существует в списке. Удаление на основе позиции int, вероятно, завершилось неудачей, поскольку другие элементы были удалены до него, и его позиция не была обновлена. Кроме того, где объявлено «removeInt»? Я этого не вижу..

3. Должно быть, я не включил эту часть кода. Я попытался преобразовать в вектор, и теперь я получаю исключение ConcurrentModificationException. Вздох. Вероятно, мне следует сделать репост :/

Ответ №3:

Добавление приведения для обозначения int как объекта сработало для меня. blossomArrayList.remove((Object)myint);

таким образом, его не путают с индексом.