Reputation: 11688
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)
Upvotes: 0
Views: 113
Reputation: 11688
OK found it, i updated the MapActivity from another Thread....
You must make sure you're adding OverlayItems from the UI thread.
Upvotes: 1
Reputation: 3349
mapOverlays.remove(item); looks like the culprit to me. If you remove an item directly like that while you are iterating over the list, it will result in a concurrentmodificationexceiption.
Use your iterator to remove things rather than doing it directly.
Upvotes: 0