#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);
таким образом, его не путают с индексом.