java.util.ConcurrentModificationException dans Android animation
Il y a quelque chose que je m'ennuie avec la notion de Synchronisation de code Android.
Scénario
Il y a toujours 3 éléments sur l'écran. Chaque image est stockée dans un ArrayList (lstGraphics). Pour cela j'utilise une SurfaceView. Une fois que l'utilisateur clique sur une image, l'image du marché supprimée et une nouvelle sera ajouté.
Des exemples de Code:
AnimationHideThread
...
@Override
public void run() {
Canvas c;
while (run) {
c = null;
try {
c = panel.getHolder().lockCanvas(null);
synchronized (panel.getHolder()) {
panel.updatePhysics();
panel.manageAnimations();
panel.onDraw(c);
}
} finally {
if (c != null) {
panel.getHolder().unlockCanvasAndPost(c);
}
}
}
}
...
De sorte que vous pouvez semblent d'abord je updatePhysics(). Cela signifie que je calculer la direction où chaque image se déplacer vers. Ici je vais également supprimer cliqué sur les images de ma liste. Après que je vérifie si j'ai besoin d'ajouter un nouvel Article dans ma liste de manageAnimations() et puis la dernière étape pour attirer toute chose.
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
....
public void manageAnimations()
{
synchronized (this.getHolder()) {
...
while (lstGraphics.size()<3) {
lstGraphics.add(createRandomGraphic());
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (getHolder()) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//... check if a image has been clicked and then set its property
graphic.setTouched(true);
}
}
return true;
}
}
public void updatePhysics() {
synchronized (getHolder()) {
for (Graphic graphic : lstGraphics) {
//.... Do some checks
if (graphic.isTouched())
{
lstGraphics.remove(graphic);
}
}
}
}
@Override
public void onDraw(Canvas canvas) {
///draw the backgrounds and each element from lstGraphics
}
public class Graphic {
private Bitmap bitmap;
private boolean touched;
private Coordinates initialCoordinates;
....
}
L'erreur que j'obtiens est:
> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): Uncaught handler: thread Thread-12 exiting due to uncaught exception
> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): java.util.ConcurrentModificationException
> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:66)
> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at com.test.customcontrols.Panel.updatePhysics(Panel.java:290)
> 03-01 10:01:53.365: ERROR/AndroidRuntime(454): at com.test.customcontrols.AnimationHideThread.run(AnimationHideThread.java:41)
Toute aide est grandement appréciée. Merci.
Vous devez vous connecter pour publier un commentaire.
Votre problème est dans votre méthode physique, où vous ajoutez le graphique et la liste
la combinaison de
for(Graphic graphic : lstGraphics)
etlst.Graphics.remove(graphic);
causes de la ConcurrentModificationException parce que vous êtes en cours d'exécution sur votre liste et en même temps essayer de la modifier.Jusqu'à présent, je sais que deux solutions:
Utilisation d'un Itérateur, si l'un est disponible (jamais codé pour Android pour l'instant).
utiliser une deuxième liste pour stocker les éléments à supprimer et de les supprimer par la suite
Iterator
. La création d'objets inutiles dans une boucle de jeu généralement une mauvaise idée..Comme @idefix dit, vous pouvez facilement obtenir ConcurrentModificationException en monothread contexte comme celui-ci:
Vous pouvez utiliser CopyOnWriteArrayList comme ci-dessous:
C'est ma méthode à l'aide de @idefix deuxième solution:
Merci @idefix +1