Android LinkedList ConcurrentModificationException SurfaceVi



我有一个SurfaceView,用户可以绘制多个位图并对其进行修改(贴纸(。贴纸保存在一个LinkedList中,该在MotionEvent.ACTION_DOWN上迭代以查找用户正在触摸的贴纸:

private void setActiveSticker(float x, float y) {
    Iterator<Sticker> stickersDesc = mStickers.descendingIterator();
    while (stickersDesc.hasNext()) {
        Sticker sticker = stickersDesc.next();
        if (sticker.collider(x, y)) {
            mActiveSticker = sticker;
            mMode = MODE_DRAG;
            break;
        }
        mStickers.remove(mActiveSticker);
        mStickers.add(mActiveSticker);
    }
}

LinkedList还被迭代,以便在操作SurfaceView时将每个Canvas绘制到它们:

@Override
public void draw (Canvas canvas) {
    super.draw(canvas);
    canvas.drawBitmap(mBitmap, mMatrix, mPaint);
    for (Sticker sticker : mStickers) {
        sticker.draw(canvas);
    }
}

这就是我得到ConcurrentModificationException的地方:

09-28 08:56:41.769  19832-24370/com.example.ex E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-5279
Process: com.example.ex, PID: 19832
java.util.ConcurrentModificationException
        at java.util.LinkedList$LinkIterator.next(LinkedList.java:124)
        at com.example.ex.utilities.DrawingSurface.draw(DrawingSurface.java:133)
        at com.example.ex.utilities.DrawingThread.onSurfaceUpdate(DrawingThread.java:95)
        at com.example.ex.utilities.DrawingThread.run(DrawingThread.java:46)

SurfaceViewdraw()方法由一个单独的Thread调用:

public class DrawingThread extends Thread {
    volatile boolean mRunning = false;
    private long mRefreshRate;
    private DrawingSurface mSurface;
    public DrawingThread (DrawingSurface surface, long time) {
        super();
        mSurface = surface;
        mRefreshRate = time;
    }
    public void setRunning (boolean run) {
        mRunning = run;
    }
    @Override
    public void run() {
        while (mRunning) {
            try {
                sleep(mRefreshRate);
                onSurfaceUpdate();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }
    }
    public void onSurfaceChanged(Configuration config, Point fit, float ratio) {
        float width, height;
        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            width = fit.y * ratio;
            height = fit.y;
        } else if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
            width = fit.x;
            height = fit.x / ratio;
        } else {
            width = fit.x;
            height = fit.x / ratio;
        } mSurface.getHolder().setFixedSize((int) width, (int) height);
    }
    private void onSurfaceUpdate() {
        Canvas canvas = null;
        try {
            canvas = mSurface.getHolder().lockCanvas();
            synchronized (mSurface.getHolder()) {
                mSurface.draw(canvas);
            }
        } finally {
            if (canvas != null) {
                mSurface.getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }
}

我尝试在setActiveSticker()迭代LinkedList之前暂停线程,并在循环完成后恢复,以避免同时进行两种修改。即使这似乎不被推荐。我想知道如何在没有此错误的情况下迭代LinkedList,或者是否有更好的方法来实现相同的功能。

这是

正常的。循环时无法更改基础Collection。您可以使用具有添加和删除项的列表迭代器

private void setActiveSticker(float x, float y) {
    ListIterator<Sticker> stickersDesc = mStickers.descendingIterator();
    while (stickersDesc.hasNext()) {
        Sticker sticker = stickersDesc.next();
        if (sticker.collider(x, y)) {
            stickersDesc.remove();
            stickersDesc.add(sticker);
            mMode = MODE_DRAG;
            return;
        }
    }
}

我找到了解决方案。我没有迭代LinkedListIteratordraw()中的ListIterator,它们都可以产生一个ConcurrentModificationException,而是将LinkedList转换为一个简单的数组,如下所示:

Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
for(Sticker sticker : stickers) {
    canvas.drawBitmap(sticker.getBitmap(), sticker.getMatrix(), sticker.getPaint());
}

我也保留了最初发布setActiveSticker()方法,因为它没有产生任何错误。我在本文中标题为"避免 [A] 多线程环境中的 ConcurrentModificationException ">的一小部分选项中找到了我正在寻找的答案:使用迭代器时如何避免 ConcurrentModificationException。

编辑:我的新绘制方法基于@fadden的提示:

public void drawSurface(Canvas canvas) {
    canvas.drawBitmap(mBitmap, mMatrix, mPaint);
    Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
    for (Sticker sticker : stickers) {
        canvas.drawBitmap(sticker.getBitmap(), sticker.getMatrix(), sticker.getPaint());
    }
}

相关内容

  • 没有找到相关文章

最新更新