我有一个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
也会被迭代,以便在操作时将每个Canvas
绘制到SurfaceView
的{{1}}:
@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)
draw()
的{{1}}方法由单独的SurfaceView
调用:
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);
}
}
}
}
中LinkedList
迭代之前暂停线程,并在完成循环后重新开始,以避免同时发生这两个修改。即使这似乎没有被推荐。我想知道如何在没有此错误的情况下迭代setActiveSticker()
,或者是否有更好的方法来实现相同的功能。
答案 0 :(得分:0)
这很正常。在循环时,您无法更改基础Collection
。您可以使用包含添加和删除项目的ListIterator
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;
}
}
}
答案 1 :(得分:0)
我找到了解决方案。我没有迭代LinkedList
,Iterator
或ListIterator
中的draw()
,而是ConcurrentModificationException
,我转换了LinkedList
一个简单的数组,如:
Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
for(Sticker sticker : stickers) {
canvas.drawBitmap(sticker.getBitmap(), sticker.getMatrix(), sticker.getPaint());
}
我还保留了setActiveSticker()
方法,就像我最初发布它一样,考虑到它没有产生任何错误。我在一篇名为&#34;避免ConcurrentModificationException的选项列表中找到了我正在寻找的答案:[A]多线程环境&#34; :How To Avoid ConcurrentModificationException When Using An Iterator。
修改强> 我的新绘制方法基于@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());
}
}