Asaf Nevo
Asaf Nevo

Reputation: 11688

Android Concurrent Modification Error MapOverlays

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

Answers (2)

Asaf Nevo
Asaf Nevo

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

Jon F Hancock
Jon F Hancock

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

Related Questions