I'm having an issue with an android application.
I have a thread that constantly iterators over a list or shapes, updates their positions, and sometimes removes an item from the list. At the end of the thread's while loop it calls postInvalidate() to prompt a repaint.
Here is the code where modification to the ArrayList happens.
Iterator<Shape> iterator = this.myList.iterator();
while (iterator.hasNext()) {
Shape nextShape = iterator.next();
nextShape.move();
if(condition) {
iterator.remove()
}
}
The onDraw method uses a for each loop to draw each of those items. I am getting concurrent modification in the onDraw method despite only modifying the list through the iterator. I've tried CopyOnWriteArrayList and Collections.synchronized with the same results.
Any help would be appreciated.
There's a couple of ways to solve this. One would be to use a synchronized block in the thread and in onDraw, but that would prevent the 2nd thread from running at the same time as the UI thread.
I think the best way is for you to use two collections. Your code should look like this
onDraw(){
synchronized(myList){
//Do your draw code. Get the iterator inside this block
}
}
threadFunction(){
List threadList;
while(1){
//Update threadList, which holds all the objects
synchronized(myList){
myList = threadList.copy(); //Do a deep copy, don't just copy over the reference
}
postInvalidate();
}
}
This will make your draw function operate on a copy of the list made at the end of an iteration. If you're working on a deep copy, you won't get any synchronization problems as the thread isn't altering the same list. The synchronized blocks will stop the thread from overwriting the draw function's copy during a draw. The only remaining issue is that the overwrite of the list in the thread will hang until a draw is done, but since updating it more frequently than that won't show on screen anyway, my guess is that's acceptable.