Android LinkedList ConcurrentModificationException SurfaceView 线程
Android LinkedList ConcurrentModificationException SurfaceView Thread
我有一个 SurfaceView
,用户可以在其中绘制多个位图并进行修改(贴纸)。贴纸保存在 LinkedList
中,该 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)
SurfaceView
的 draw()
方法被单独的 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()
中迭代之前暂停线程,并在循环完成后恢复,以避免同时发生两个修改。尽管这似乎不被推荐。我想知道如何在不出现此错误的情况下迭代 LinkedList
,或者是否有更好的方法来实现相同的功能。
这是正常的。循环时无法更改基础 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;
}
}
}
我找到了解决办法。我没有在 draw()
中迭代 LinkedList
、Iterator
或 ListIterator
,它们都可以生成 ConcurrentModificationException
,而是转换了 LinkedList
到一个简单的数组,像这样:
Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
for(Sticker sticker : stickers) {
canvas.drawBitmap(sticker.getBitmap(), sticker.getMatrix(), sticker.getPaint());
}
考虑到它没有产生任何错误,我还保留了最初发布的 setActiveSticker()
方法。我在本文中标题为 "To Avoid ConcurrentModificationException In [A] Multi-Threaded Environment" 的一小部分选项中找到了我正在寻找的答案: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());
}
}
我有一个 SurfaceView
,用户可以在其中绘制多个位图并进行修改(贴纸)。贴纸保存在 LinkedList
中,该 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)
SurfaceView
的 draw()
方法被单独的 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()
中迭代之前暂停线程,并在循环完成后恢复,以避免同时发生两个修改。尽管这似乎不被推荐。我想知道如何在不出现此错误的情况下迭代 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;
}
}
}
我找到了解决办法。我没有在 draw()
中迭代 LinkedList
、Iterator
或 ListIterator
,它们都可以生成 ConcurrentModificationException
,而是转换了 LinkedList
到一个简单的数组,像这样:
Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
for(Sticker sticker : stickers) {
canvas.drawBitmap(sticker.getBitmap(), sticker.getMatrix(), sticker.getPaint());
}
考虑到它没有产生任何错误,我还保留了最初发布的 setActiveSticker()
方法。我在本文中标题为 "To Avoid ConcurrentModificationException In [A] Multi-Threaded Environment" 的一小部分选项中找到了我正在寻找的答案: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());
}
}