I'm making a server request and when I receive the response from server, I'm executing on UI Thread a ClusterManager.addItem()
but this items are not painting in the map, only when I make a zoom update (+,-) newly added items starts appearing. I also tried to debug the renderer, but onBeforeClusterRendered
/ onBeforeClusterItemRendered
are not getting called until I update the zoom in map.
Any ideas how to refresh map/clusterManager/markers?
MarkerManager markerManager = new MarkerManager(map);
clusterManager = new ClusterManager<TweetClusterItem>(getActivity(), map, markerManager);
clusterManager.setRenderer(new TweetClusterRenderer(getActivity(), map, clusterManager, defaultMarker));
clusterManager.setOnClusterClickListener(this);
clusterManager.setOnClusterInfoWindowClickListener(this);
clusterManager.setOnClusterItemClickListener(this);
clusterManager.setOnClusterItemInfoWindowClickListener(this);
UiSettings uiSettings = map.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
uiSettings.setMyLocationButtonEnabled(false);
map.setOnCameraChangeListener(clusterManager);
map.setOnMarkerClickListener(clusterManager);
map.setOnInfoWindowClickListener(clusterManager);
map.setOnMapClickListener(this);
mClusterManager.cluster();
force re-clustering items when you after added new item.
Seems that I found a workaround.
ClusterManager uses a renderer, in this case it inherits from DefaultClusterRenderer which uses a internal cache, a cache of markers that are added to map. You can access directly to the added markers on the map, I don't use the info window, so i add marker options.title() an ID for later find this marker, so:
@Override
protected void onBeforeClusterItemRendered(TweetClusterItem item, MarkerOptions markerOptions) {
.... Blabla code....
markerOptions.title(Long.toString(tweet.getId()));
.... Blabla code....
}
and when I want to reload the clusterItem I call this method:
/**
* Workarround to repaint markers
* @param item item to repaint
*/
public void reloadMarker(TweetClusterItem item) {
MarkerManager.Collection markerCollection = clusterManager.getMarkerCollection();
Collection<Marker> markers = markerCollection.getMarkers();
String strId = Long.toString(item.getTweet().getId());
for (Marker m : markers) {
if (strId.equals(m.getTitle())) {
m.setIcon( ICON TO SET);
break;
}
}
}
Maybe is a little hacky but it works and I din't found any other way to do this. If you found another better way, please share :)
You can get specific markers that correspond to their cluster or cluster items and vice versa in O(1) using DefaultClusterRenderer's getMarker(), getCluster() and getClusterItem() (set your own renderer to access the renderer object).
Use these methods to change the markers of your items whenever you need.
...
DefaultClusterRenderer mRenderer = ...
mClusterManager.setRenderer(mRenderer);
...
public void reloadMarker(ClusterItem item) {
mRenderer.getMarker(item).setIcon(YOUR_ICON);
}
I wouldn't recommend saving them anywhere else though, since those methods return the renderer's cache objects.
I was having the same exact problem. None of the suggested solutions were working for me. I made a class which extends the DefaultClusterRenderer and adds the public method updateClusterItem(ClusterItem clusterItem) which will force the Marker associated with that ClusterItem to be re-rendered (works with both clusters and cluster items).
import android.content.Context;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.view.DefaultClusterRenderer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public abstract class CustomClusterRenderer<T extends ClusterItem>
extends DefaultClusterRenderer<T> {
private ClusterManager<T> mClusterManager;
private Map<T, Marker> mClusterMap = new HashMap<>();
public CustomClusterRenderer(Context context, GoogleMap map,
ClusterManager<T> clusterManager) {
super(context, map, clusterManager);
mClusterManager = clusterManager;
}
@Override
@CallSuper
protected void onClusterItemRendered(T clusterItem, Marker marker) {
super.onClusterItemRendered(clusterItem, marker);
mClusterMap.remove(clusterItem);
cleanCache();
}
@Override
@CallSuper
protected void onClusterRendered(Cluster<T> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
for (T clusterItem : cluster.getItems()) {
mClusterMap.put(clusterItem, marker);
}
cleanCache();
}
public void updateClusterItem(T clusterItem) {
Marker marker = getMarker(clusterItem);
boolean isCluster = false;
if (marker == null) {
marker = mClusterMap.get(clusterItem);
isCluster = marker != null;
}
if (marker != null) {
MarkerOptions options = getMarkerOptionsFromMarker(marker);
if (isCluster) {
Cluster cluster = getCluster(marker);
onBeforeClusterRendered(cluster, options);
} else {
onBeforeClusterItemRendered(clusterItem, options);
}
loadMarkerWithMarkerOptions(marker, options);
}
}
private void cleanCache() {
ArrayList<T> deleteQueue = new ArrayList<>();
Collection<Marker> clusterMarkers = mClusterManager
.getClusterMarkerCollection().getMarkers();
for (T clusterItem : mClusterMap.keySet()) {
if (!clusterMarkers.contains(mClusterMap.get(clusterItem))) {
deleteQueue.add(clusterItem);
}
}
for (T clusterItem : deleteQueue) {
mClusterMap.remove(clusterItem);
}
deleteQueue.clear();
}
private MarkerOptions getMarkerOptionsFromMarker(@NonNull Marker marker) {
MarkerOptions options = new MarkerOptions();
options.alpha(marker.getAlpha());
options.draggable(marker.isDraggable());
options.flat(marker.isFlat());
options.position(marker.getPosition());
options.rotation(marker.getRotation());
options.title(marker.getTitle());
options.snippet(marker.getSnippet());
options.visible(marker.isVisible());
options.zIndex(marker.getZIndex());
return options;
}
private void loadMarkerWithMarkerOptions(@NonNull Marker marker,
@NonNull MarkerOptions options) {
marker.setAlpha(options.getAlpha());
marker.setDraggable(options.isDraggable());
marker.setFlat(options.isFlat());
marker.setPosition(options.getPosition());
marker.setRotation(options.getRotation());
marker.setTitle(options.getTitle());
marker.setSnippet(options.getSnippet());
marker.setVisible(options.isVisible());
marker.setZIndex(options.getZIndex());
marker.setIcon(options.getIcon());
marker.setAnchor(options.getAnchorU(), options.getAnchorV());
marker.setInfoWindowAnchor(options.getInfoWindowAnchorU(), options.getInfoWindowAnchorV());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With