Reputation: 581
I am making a game and i read all about concurrent modification exception when removing/modifying the array list while iterating through it, but i still have a problem.
I want to remove object when the screen is touched and the objects x,y align with the touched x,y but and when that happens, i put that touched object into a new collection for the removal, but it removes ( sometimes) object but 3-4s later which doesn't make much sense to me and also gives the concurrent modification exception 10-15s later. If anyone notices anything in my code, let me know...
public void checkTouch(MotionEvent arg1) {
int x = (int) arg1.getX();
int y = (int) arg1.getY();
synchronized(surfaceHolder){
/*check every creature for the coordinates*/
Iterator<Sprite> it = creature.iterator();
while(it.hasNext())
{
Sprite current = it.next();
int sglX = current.getX();
int sglY = current.getY();
if(sglX>=x && x<=(sglX+current.getWidth())){
if(sglY>=y && y<=(sglY-current.getHeight())){
destroy(current);
break; //when we found one object, don't iterate no more
}
}
}
}
}
And destory method:
private void destroy(Sprite removed) {
/*adds the creature clicked to the recicle bin to be destroyed*/
recicle.add(removedSeagull); //recicle is the other collection
}
And i call this creature.removeAll(recicle);
before i draw creatures on the canvas so it doesn't get into conflict with other iterator.
Here is the stack trace:
07-11 21:06:00.905: E/AndroidRuntime(14221): FATAL EXCEPTION: Thread-83
07-11 21:06:00.905: E/AndroidRuntime(14221): java.util.ConcurrentModificationException
07-11 21:06:00.905: E/AndroidRuntime(14221): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)
07-11 21:06:00.905: E/AndroidRuntime(14221): at com.example.creatures.GameView$GameThread.drawCreatures(GameView.java:292)
07-11 21:06:00.905: E/AndroidRuntime(14221): at com.example.creatures.GameView$GameThread.doDraw(GameView.java:283)
07-11 21:06:00.905: E/AndroidRuntime(14221): at com.example.creatures.GameView$GameThread.run(GameView.java:245)
I figured it may be the drawing method so maybe the fault is there, here it is:
private void drawCreatures(Canvas c) {
/*iterate through the array and update all the creatures*/
synchronized(surfaceHolder){
Iterator<Sprite> it = creature.iterator();
while(it.hasNext())
{
Sprite current = it.next();
current.draw(c);
}
}
}
And the run method of the GameThread is called in the GameView ( which extends surface holder ) like so:
@Override
public void surfaceCreated(SurfaceHolder arg0) {
thread.setRunning(true);
thread.start();
startTimer(1500);
}
And also the run method of the thread is this:
@Override
public void run(){
while(run){
Canvas c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
if (mode == STATE_RUNNING){
doDraw(c);
}
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, don't leave the Surface in an
// inconsistent state
if (c != null) {
/*unlocks the canvas and shows the image drawn by the doDraw method*/
surfaceHolder.unlockCanvasAndPost(c);
}
"drawCreatures" method is called in the "doDraw" method.
Upvotes: 1
Views: 715
Reputation: 1700
If you are fine with stale results from the iterator, then you can use CopyOnWriteArrayList http://developer.android.com/reference/java/util/concurrent/CopyOnWriteArrayList.html
Basically it ensures that the iterator shows contents that were present at the time the iterator was created. The only change is that iterator.remove() will not work on the iterators returned by this list. You have to remove it from the actual list.
Hope that helps,
Nagesh
Upvotes: 2
Reputation: 1902
Why you don't use default method of iterator
?
Write it.remove()
instead of destroy(current);
Upvotes: 0