Reputation: 33
it seems like I've been getting the concurrent modification exception no matter what I do. I did some research and from what I understand this exception occurs when you try to edit a list while iterating through it at the same time. But I still can't figure out exactly whats causing it. So I was hoping some more experienced people could help me figure out where I went wrong here. Here's my code.
package com.gametest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class GameSurfaceView extends Activity implements OnTouchListener {
double ran;
int touchX, touchY, screenWidth, screenHeight, objX, objY;
static boolean canUpdate;
static int enemyCount;
static MyView v;
static Bitmap orb, explosion;
static List<Sprite> enemiesList = new ArrayList<Sprite>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
v = new MyView(this);
v.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent me) {
touchX = (int) me.getX();
touchY = (int) me.getY();
for (Sprite sprite : enemiesList) {
sprite.checkTouch(touchX, touchY);
}
return true;
}
});
canUpdate = true;
ran = 0;
orb = BitmapFactory.decodeResource(getResources(), R.drawable.blue_orb);
explosion = BitmapFactory.decodeResource(getResources(), R.drawable.explosion);
createEnemies();
setContentView(v);
}
private synchronized void createEnemies() {
if (enemyCount < 5) {
screenWidth = v.getWidth();
screenHeight = v.getHeight();
int listLength = enemiesList.size();
enemiesList.add(new Sprite(v, orb, explosion, screenWidth, screenHeight, listLength));
enemyCount = enemyCount + 1;
}
}
public static synchronized void checkECount(int id) {
canUpdate = false;
enemyCount = enemyCount - 1;
enemiesList.remove(id);
int index = 0;
Iterator<Sprite> itr = enemiesList.iterator();
while(itr.hasNext()) {
Sprite s = itr.next();
s.ID = index;
index++;
}
canUpdate = true;
}
@Override
protected void onPause() {
super.onPause();
v.pause();
}
@Override
protected void onResume() {
super.onResume();
v.resume();
}
public class MyView extends SurfaceView implements Runnable {
Thread t = null;
SurfaceHolder holder;
boolean isItOk = false;
public MyView(Context context) {
super(context);
holder = getHolder();
}
@Override
public void run() {
while (isItOk == true) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas c = holder.lockCanvas();
if(canUpdate){
canvas_draw(c);
}
holder.unlockCanvasAndPost(c);
}
}
protected synchronized void canvas_draw(Canvas canvas) {
canvas.drawARGB(255, 50, 10, 10);
String ranString = Integer.toString(screenHeight);
ran = Math.random() * 5;
if (ran > 3) {
createEnemies();
}
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(15);
canvas.drawText(ranString, 10, screenHeight - 25, paint);
for (Sprite sprite : enemiesList) {
sprite.sprite_draw(canvas);
}
}
public void pause() {
isItOk = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
}
break;
}
t = null;
}
public void resume() {
isItOk = true;
t = new Thread(this);
t.start();
}
}
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
return false;
}
}
Here's the logCat
01-28 23:25:56.749: E/AndroidRuntime(5452): FATAL EXCEPTION: main
01-28 23:25:56.749: E/AndroidRuntime(5452): java.util.ConcurrentModificationException
01-28 23:25:56.749: E/AndroidRuntime(5452): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.gametest.GameSurfaceView$1.onTouch(GameSurfaceView.java:42)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.View.dispatchTouchEvent(View.java:7122)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1877)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1925)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1379)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.app.Activity.dispatchTouchEvent(Activity.java:2396)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1873)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.View.dispatchPointerEvent(View.java:7307)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3172)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3117)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4153)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4132)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4224)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.os.MessageQueue.nativePollOnce(Native Method)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.os.MessageQueue.next(MessageQueue.java:125)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.os.Looper.loop(Looper.java:124)
01-28 23:25:56.749: E/AndroidRuntime(5452): at android.app.ActivityThread.main(ActivityThread.java:4745)
01-28 23:25:56.749: E/AndroidRuntime(5452): at java.lang.reflect.Method.invokeNative(Native Method)
01-28 23:25:56.749: E/AndroidRuntime(5452): at java.lang.reflect.Method.invoke(Method.java:511)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
01-28 23:25:56.749: E/AndroidRuntime(5452): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
01-28 23:25:56.749: E/AndroidRuntime(5452): at dalvik.system.NativeStart.main(Native Method)
Upvotes: 1
Views: 577
Reputation: 13705
The issue is that you might be modifying "enemiesList" (removing/adding elements for example), while the list is being itarated here:
for (Sprite s : enemiesList) {
s.ID = index;
index++;
}
Try making that method synchronized and see what happens (as well as the one that adds elements into the list):
public synchronized static void checkECount(int id) {
canUpdate = false;
enemyCount = enemyCount - 1;
enemiesList.remove(id);
int index = 0;
for (Sprite s : enemiesList) {
s.ID = index;
index++;
}
canUpdate = true;
}
I actually see a potential disaster here when "createEnemies" is being called, give it a try and see what happens...
Hope this Helps...
Regards!
Upvotes: 1
Reputation: 2808
If the traversal operations on your list vastly outnumber the mutative operations, you might want to use a CopyOnWriteArrayList. It has a snapshot-style iterator that allows you to iterate through the list even if it's being changed in the meantime. Be mindful though, like the name suggests, it creates an entirely new copy of the underlying array every time you make a change to it. IE, if you're making too many changes, it might be a performance hit.
Upvotes: 0
Reputation: 1487
This looks like your problem:
for (Sprite s : enemiesList) {
s.ID = index;
index++;
}
Modifying a varible from the Sprite class while iterating through it is throwing the exception. Try declaring the method synchronized like this:
protected synchronized void canvas_draw(Canvas canvas) {
or use an Iterator.
Upvotes: 0