First at all, congratulations!!! Great job (we users ask for something but not thanks given). I started to use this library for few days ago (clustering) and I need to show markers in map, and when user click on them, it must to show the info window showing some information about the marker. Inside this information there is a photo profile from url (http...). As you know, the photo has to be taken in a background task, so when onClusterItemClick listener go out, it downloads the photo, and when it ends, callback has to show info window, so in onClusterItemClick listener interface I return true ( I have managed the event and this way info window is not showing) but when callback from image download has to show info window but it can not call showInfoWindow method from a marker object because I have no reference to it. Also, I need to consult some information from cluster in InfoWindowAdapter, and in this case, I know the marker but not the clusterItem information.
As solution, I have tried to give two method to DefaultClusterRenderer
protected Marker getMarker(T item) {
return mMarkerCache.get(item);
}
protected T getCluster(Marker marker) {
return mMarkerCache.get(marker);
}
This way I resolve my problem and every was fine until I recived this crash report:
01-30 17:42:50.685: E/ACRA(15290): ACRA caught a ConcurrentModificationException exception for info.si2.android.unidogs.app. Building report.
01-30 17:42:53.513: E/AndroidRuntime(15290): FATAL EXCEPTION: Thread-8895
01-30 17:42:53.513: E/AndroidRuntime(15290): java.util.ConcurrentModificationException
01-30 17:42:53.513: E/AndroidRuntime(15290): at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792)
01-30 17:42:53.513: E/AndroidRuntime(15290): at java.util.HashMap$KeyIterator.next(HashMap.java:819)
01-30 17:42:53.513: E/AndroidRuntime(15290): at java.util.AbstractSet.removeAll(AbstractSet.java:110)
01-30 17:42:53.513: E/AndroidRuntime(15290): at com.google.maps.android.clustering.view.DefaultClusterRenderer$RenderTask.run(DefaultClusterRenderer.java:383)
01-30 17:42:53.513: E/AndroidRuntime(15290): at java.lang.Thread.run(Thread.java:856)
Are this and my methods relationated or is this a independient issue?
Can you confirm me this methods are a good idea in the library?
Thank you, I hope to hear soon about you.
To track any data associated with the marker, it is best to create a hashmap of marker ID vs. you data model, the best place to implement this is also in the renderer class by implementing the method:
@Override
protected void onClusterItemRendered(Person person, Marker marker) {
super.onClusterItemRendered(person, marker);
markerPersonMap.put(marker.getId(), person);
}
When implementing the method, onBeforeClusterItemRendered, you have MarkerOptions object passed in as the second parameter. You can then modify it from there.
markerOptions.title("Blah")
.snippet("some property from the first parameter object...")
.flat(true);
and finally, on your onInfoWindowClick method, you can access your object (ClusterItem) by doing
@Override
public void onInfoWindowClick(Marker marker) {
final Person thePersonOnThisMarker = markerPersonMap.get(marker.getId());
// do something with this person/ClusterItem associated with this marker / markerInfoWindow
}
First thanks, but I need to resolve some questions:
1.- Why is better to create a hashmap if inside library there are two structures which have those data, why don't reuse them to get info? The way you commented resolves just one question: given a marker -> get their data, but what will happen when you need a marker from data? I know I can create another hashmap inverse, but I don't know if it is a good idea repeat the same structure than library has.
2.- Yes, I can manage some information about marker in onBeforeClusterItemRendered like snippet, title, etc but I need to call showInfoWindow method from a marker in a determinate time, so I need to get a marker from cluster data.
By the way, crash report was because of sometimes I called showInfoWindow from marker when zoom could had changed and marker didn't exist. I resolved that and now all is working but I would like to know why is bad idea (may be not) giving two method to DefaultClusterRenderer class:
protected Marker getMarker(T item) {
return mMarkerCache.get(item);
}
protected T getCluster(Marker marker) {
return mMarkerCache.get(marker);
}
I agree with you. Inside the static class MarkerCache
This is a good point - I think initial design concerns were misguided - the clusterer has no concept of markers intentionally. I can see that has hampered usability.
The idea to add those protected methods sounds good to me.
Would you like to send a pull request to expose those?
Pull request sent
onClusterItemRendered method gets called only when we zoom map .
Thanks for the pull requests, all. This is in 0.3.2.
Oh yes, making these maps publicly accessible to get ClusterItem for Marker is a must! This helped me find that mapping in the DefaultClusterRenderer though.
How else would you be able to update a ClusterItem's position when dragged for example? You only have the Marker in the OnMarkerDragListener. The problem with rolling your own map, besides duplicating an already present and managed cache, is that Markers are never removed from your map when they're removed from the cluster renderer! So this would surely leak memory.
libary ClusterItem where ?
http://www.chuanroi.net/
@ericpanorel Thank you so much!!!!!
Most helpful comment
To track any data associated with the marker, it is best to create a hashmap of marker ID vs. you data model, the best place to implement this is also in the renderer class by implementing the method:
When implementing the method, onBeforeClusterItemRendered, you have MarkerOptions object passed in as the second parameter. You can then modify it from there.
and finally, on your onInfoWindowClick method, you can access your object (ClusterItem) by doing