In my app i have a MapView with custom MapOverlays.
I've override the onDraw method so i will be able to cluster overlay items which are on the same position - and it work great.
I'm now trying to add a large bunch of markers and i get a Concurrent Modification Error
although i had synchronized the method and the right object..
I think it has something to do with the onDraw method which is called many times each time it is needed (which is ok as read in some threads here) - and it must have been updating the ArrayList at the same time it tries to iterate it.
My question is why ?i did synchronized it... it should be locked..
My function which is called from onDraw():
private synchronized ArrayList<OverlayItem> createOverlayItems(MapView mapView)
{
Projection projection = mapView.getProjection();
int minPixelDistance = app.getPixels(50); //distance allowed between 2 markers
synchronized (fullMapOverlays) {
OverlayItem me = getOverlayItem(ME);
fullMapOverlays.remove(me);
mapOverlays.clear();
mapOverlays.addAll(fullMapOverlays);
Iterator<OverlayItem> overlayIterator = fullMapOverlays.iterator();
while (overlayIterator.hasNext())
{
OverlayItem item = overlayIterator.next();
Point currentItemPoint = projection.toPixels(item.getPoint(), null);
if (!isPointInScreen(currentItemPoint))
continue;
else if (item.getTitle().equals(ME) && item.getSnippet().equals(ME))
continue;
else if (!mapOverlays.contains(item))
continue;
cluster.clear();
Iterator<OverlayItem> innerIterator = mapOverlays.iterator();
while (innerIterator.hasNext())
{
OverlayItem itemToCheck = innerIterator.next();
Point checkingItemPoint = projection.toPixels(itemToCheck.getPoint(), null);
if (!isPointInScreen(checkingItemPoint))
{
innerIterator.remove();
continue;
}
else if (itemToCheck.getTitle().equals(ME) && itemToCheck.getSnippet().equals(ME))
continue;
else if (itemToCheck.getTitle().equals(CLUSTER))
continue;
if (!item.equals(itemToCheck))
{
if (getPixelsDistance(currentItemPoint, checkingItemPoint) <= minPixelDistance)
{
cluster.add(itemToCheck);
innerIterator.remove();
}
}
}
if (cluster.size() > 0)
{
mapOverlays.remove(item);
cluster.add(item);
String itemsTitle = "";
for (int i=0; i<cluster.size(); i++)
{
if (i == 0)
itemsTitle += cluster.get(i).getTitle();
else
itemsTitle += "|" + cluster.get(i).getTitle();
}
OverlayItem clusterItem = new OverlayItem(cluster.get(0).getPoint(), CLUSTER, itemsTitle);
clusterItem.setMarker(boundCenterBottom(createClusterDrawable(cluster.size())));
mapOverlays.add(clusterItem);
}
}
fullMapOverlays.add(fullMapOverlays.size(), me);
mapOverlays.add(mapOverlays.size(), me);
}
return mapOverlays;
}
Lovely logcat:
01-25 00:27:47.070: W/System.err(4676): java.util.ConcurrentModificationException
01-25 00:27:47.070: W/System.err(4676): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:576)
01-25 00:27:47.070: W/System.err(4676): at com.WhosAround.Activities.Map.MapOverlay.createOverlayItems(MapOverlay.java:169)
01-25 00:27:47.070: W/System.err(4676): at com.WhosAround.Activities.Map.MapOverlay.draw(MapOverlay.java:61)
01-25 00:27:47.070: W/System.err(4676): at com.google.android.maps.Overlay.draw(Overlay.java:179)
01-25 00:27:47.075: W/System.err(4676): at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:42)
01-25 00:27:47.075: W/System.err(4676): at com.google.android.maps.MapView.onDraw(MapView.java:530)
01-25 00:27:47.075: W/System.err(4676): at android.view.View.draw(View.java:6933)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.View.draw(View.java:6936)
01-25 00:27:47.075: W/System.err(4676): at android.widget.FrameLayout.draw(FrameLayout.java:357)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.View.draw(View.java:6936)
01-25 00:27:47.075: W/System.err(4676): at android.widget.FrameLayout.draw(FrameLayout.java:357)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.View.draw(View.java:6936)
01-25 00:27:47.075: W/System.err(4676): at android.widget.FrameLayout.draw(FrameLayout.java:357)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
01-25 00:27:47.075: W/System.err(4676): at android.view.View.draw(View.java:6936)
01-25 00:27:47.075: W/System.err(4676): at android.widget.FrameLayout.draw(FrameLayout.java:357)
01-25 00:27:47.075: W/System.err(4676): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1917)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewRoot.draw(ViewRoot.java:1530)
01-25 00:27:47.075: W/System.err(4676): at android.view.ViewRoot.performTraversals(ViewRoot.java:1266)
01-25 00:27:47.080: W/System.err(4676): at android.view.ViewRoot.handleMessage(ViewRoot.java:1868)
01-25 00:27:47.080: W/System.err(4676): at android.os.Handler.dispatchMessage(Handler.java:99)
01-25 00:27:47.080: W/System.err(4676): at android.os.Looper.loop(Looper.java:130)
01-25 00:27:47.080: W/System.err(4676): at android.app.ActivityThread.main(ActivityThread.java:3691)
01-25 00:27:47.080: W/System.err(4676): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 00:27:47.080: W/System.err(4676): at java.lang.reflect.Method.invoke(Method.java:507)
01-25 00:27:47.080: W/System.err(4676): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
01-25 00:27:47.080: W/System.err(4676): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
01-25 00:27:47.080: W/System.err(4676): at dalvik.system.NativeStart.main(Native Method)
OK found it, i updated the MapActivity from another Thread....
You must make sure you're adding OverlayItems from the UI thread.