I have a map with custom overlay and a bunch of markers. Because I'm doing markers grouping when zoom change happens I have to clear overlay, regroup items for new zoom and lay then on map again. I'm doing this in backround thread to get things smooth. So you click to zoom, markers disappear, busy indicator shows in corner and new markers appear on map. all is smooth as it should however I get concurent modification exception when you zoom twice in row or zoom in and zoom out immediatelly. I've read plenty about this but none solutions are ok for me yet. For example moving map moification to onPostExecute which is on UI does prevent this but freezes map for a time markers are drawn and it looses its smoothness. I tried to make markders list on itemized overlay synchronized list but did not help. How can I prevent this?
This is what I call on zoom change:
private void drawItems() {
final MyMapView mw = this.mapView;
//remove existing first
//mw.getOverlays().remove(stuffOverlay);
stuffOverlay.clearAll();
//mw.invalidate();
new AsyncTask<String, Integer, String>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
((ProgressBar)findViewById(R.id.mapProgressBar)).setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(String... params) {
//get items on map
HashMap<String, JSONArray> groupedItems = getItemsForZoom(mw.getZoomLevel());
if (groupedItems==null)
return "done";
//create a copy of it sometimes it was throwing concurentmodificationexception
HashMap<String, JSONArray> groupedItemsCopy = new HashMap<String, JSONArray> (groupedItems);
Iterator it = groupedItemsCopy.entrySet().iterator();
while (it.hasNext()) { //loop over markers
try {
//get item
HashMap.Entry<String, Object> pair = (HashMap.Entry)it.next();
JSONArray itemsInMarker = (JSONArray) pair.getValue();
JSONObject itemData = (JSONObject) itemsInMarker.get(0);
//get truncated coordinates
String coordsKey = pair.getKey();
String[] coordsSplitted = coordsKey.split("_");
//add first marker to map
GeoPoint gp = new GeoPoint((int)(Double.parseDouble(coordsSplitted[0])*1E6), (int)(Double.parseDouble(coordsSplitted[1])*1E6));
OverlayItem markerOverlay = new OverlayItem(gp, "marker", "snipper text");
Drawable markerPic = ServerCall.drawableFromUrl(((JSONObject)((JSONObject)itemData.get("picture")).get("1")).get("picture_full")+"_0.png");
//markerPic.setBounds(0, 0, markerPic.getIntrinsicWidth(), markerPic.getIntrinsicHeight());
markerPic.setBounds(-25, -25, 50, 50);
markerOverlay.setMarker(markerPic);
stuffOverlay.addOverlay(markerOverlay, itemData);
if (stuffOverlay.size() > 0) {
mapView.getOverlays().add(stuffOverlay);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return "done";
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
((ProgressBar)findViewById(R.id.mapProgressBar)).setVisibility(View.GONE);
mapView.invalidate();
}
}.execute();
}
This is my itemized overlay:
private class StuffOverlay extends ItemizedOverlay {
private List<OverlayItem> mOverlays = Collections.synchronizedList(new ArrayList<OverlayItem>());
private ArrayList<JSONObject> mStuff = new ArrayList<JSONObject>();
public int currentItem;
Map mMap;
public StuffOverlay(Drawable defaultMarker, Map map) {
super(boundCenterBottom(defaultMarker));
mMap = map;
populate(); //keep here
}
public void addOverlay(OverlayItem overlay, JSONObject stuffData) {
synchronized (mOverlays) {
mOverlays.add(overlay);
}
mStuff.add(stuffData);
setLastFocusedIndex(-1); //keep here
populate();
}
public void clearAll() {
synchronized (mOverlays) {
mOverlays.clear();
}
setLastFocusedIndex(-1); //keep here
populate();
}
@Override
protected OverlayItem createItem(int i) {
synchronized (mOverlays) {
return mOverlays.get(i);
}
}
@Override
public int size() {
synchronized (mOverlays) {
return mOverlays.size();
}
}
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (!shadow) {
super.draw(canvas, mapView, false);
}
}
}
And this is what I'm getting ;o(
05-30 20:45:35.485: W/dalvikvm(1139): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
05-30 20:45:35.485: E/AndroidRuntime(1139): Uncaught handler: thread main exiting due to uncaught exception
05-30 20:45:35.495: E/AndroidRuntime(1139): java.util.ConcurrentModificationException
05-30 20:45:35.495: E/AndroidRuntime(1139): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64)
05-30 20:45:35.495: E/AndroidRuntime(1139): at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:44)
05-30 20:45:35.495: E/AndroidRuntime(1139): at com.google.android.maps.MapView.onDraw(MapView.java:476)
05-30 20:45:35.495: E/AndroidRuntime(1139): at android.view.View.draw(View.java:6535)
05-30 20:45:35.495: E/AndroidRuntime(1139): at android.view.ViewGroup.drawChild(ViewGroup.java:1531)
05-30 20:45:35.495: E/AndroidRuntime(1139): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)