How to temporarily disable map marker clustering?

4.7k Views Asked by At

I am using Google Maps V2 for Android together with maps utils extension library for marker clustering. Some parts of app does not need to get clustered markers.

Is there any way to forbid clusterManager to cluster markers and after certain conditions let it cluster items again?

3

There are 3 best solutions below

2
On BEST ANSWER

I found myself another solution. I figured out that on DefaultClusterRenderer method shouldRenderAsCluster is responsible for whether the marker will be rendered as cluster or not. So I created a CustomRenderer class which extends DefaultClusterRenderer and created a method with a boolean variable to determine whether renderer should cluster or not.

public class CustomRenderer extends DefaultClusterRenderer<MarkerItem>
{
private boolean shouldCluster = true;
private static final int MIN_CLUSTER_SIZE = 1;

//Some code....

public void setMarkersToCluster(boolean toCluster)
{
    this.shouldCluster = toCluster;
}

I also override the method here that i mentioned before.

@Override
protected boolean shouldRenderAsCluster(Cluster<MarkerItem> cluster)
{
    if (shouldCluster)
    {
        return cluster.getSize() > MIN_CLUSTER_SIZE;
    }

    else
    {
        return shouldCluster;
    }
}

And now if I want to stop clustering i just call this method from the activity i want.

ClusterManager clusterManager = new ClusterManager<MarkerItem>(this, googleMap);
CustomRenderer customRenderer = new CustomRenderer(this, googleMap, clusterManager);
clusterManager.setRenderer(customRenderer);
customRenderer.setMarkersToCluster(false);
6
On

The cluster manager implementation is only capable of performing the built in clustering functionality. If you wish for certain markers to not cluster, you will need to add those markers to the map directly. When you decide to cluster those markers, you will need to remove them from the map and transfer their information to the cluster manager for it to take over.

0
On

After calling setMarkersToCluster(false) to disable clustering it tooks a while, before shouldRenderAsCluster(Cluster cluster) of the CustomRenderer is called. So if renderer.getMarker(markerItem) is called directly after disabling clustering null is returned. Waiting for some time by:

    new Handler(Looper.getMainLooper()).postDelayed(new Runnable(){
public void run(){
    Marker marker=renderer.getMarker(markerItem);
}

}, 700L);

returns a marker !=null.

This is not an ideal solution, because the waiting time might not be always work. An alternative would be to implement an event listener and an event publisher (visit Java. Correct pattern for implementing listeners) The event is produced in

    @Override
protected boolean shouldRenderAsCluster(Cluster<MarkerItem> cluster) { ...}

and sent to the observer, which was registered by the event producer.

     @Override
protected boolean shouldRenderAsCluster(Cluster<MarkerItem> cluster) {
    //start clustering if at least 5 items overlap and mShouldCluster==true
    int clusterSize = cluster.getSize();
    boolean clusteringOn=(mShouldCluster && (clusterSize > 4));
    notifyObserver(clusteringOn);
    final String msg = "shouldRenderAsCluster; act. cluster size= = " + cluster.getSize() + ". should cluster? " +  clusteringOn;
    if (BuildConfig.DEBUG) {
        Log.i(LOG_TAG, "+++" + msg);
    }
    return clusteringOn;
}

     /**
 * Renderer Settings
 * @param shouldRender =true: rendering enabled; =false: rendering disabled
 */
public void setShouldRender(boolean shouldRender) {
    mShouldCluster = shouldRender;
}
/**
 * Register the observer at the event handler
 * @param  observer event listener of the observer
 */
public void setShouldRenderListener(IOnShouldRendererListener observer) {
    mObserver=observer;
}
/**
 * Notify the observer, if the observer ist registered at the event handler,
 * @param shouldRender =true; rendering enabled; =false: rendering disabled
 */
private void notifyObserver(boolean shouldRender) {
    // Notify the observer
    if (mObserver!=null) {
        mObserver.onShouldClusterCalled(shouldRender);
    }
}

The event listener implemented in the observer class MarkerCollection2 implements IOnShouldRendererListener.

    public interface IOnShouldRendererListener {
 void onShouldClusterCalled(boolean shouldRender);
}

public void onShouldClusterCalled(boolean shouldCluster) {
    Log.i(LOG_TAG,"onShouldClusterCalled; should Cluster= " + shouldCluster);
    if (!shouldCluster){
        final MarkerItem markerItem = mMarkerList.get(mLastSelectedMarker);
        final Marker marker = mClusterRenderer.getMarker(markerItem);
        Log.i(LOG_TAG,"onShouldClusterCalled; marker!=null? " + (marker!=null));
        if (marker!=null) {
            mClusterRenderer.setShouldRender(true);
            mClusterRenderer.setShouldRenderListener(null);
            mMyInfoWindowAdapter.setClickedMarkerItem(markerItem);
            LatLng position = markerItem.getPosition();
            final CameraUpdate update;
            if (markerItem instanceof RouteMarkerItem) {
                //marker is a non clustered route marker: nothing to zoom
                update = CameraUpdateFactory.newLatLng(position);
            } else {
                // marker is a clustered station marker; zoom to MinZoomLevelNotClustered
                update = CameraUpdateFactory.newLatLngZoom(position, MIN_ZOOM_NOT_CLUSTERED);
            }
            //showInfoWindow, must run on UI thread
            final Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                public void run() {
                    marker.showInfoWindow();
                    mMap.moveCamera(update);
                }
            });
        }
    }
}

Starting showInfoWindow is done by:

     mClusterRenderer.setShouldRenderListener(this);
    mClusterRenderer.setShouldRender(false);
    mClusterManager.cluster();

When onShouldClusterCalled was called, the listener is set to null to prevent further notifications and rendering is enabled again. This works, but this is a too complex solution only for open an infoWindow. So I will stay with the maps extension library: android-maps-extension

This library does the clustering of markers and GoogleMap markers can be accessed and marker.showInfoWindow() can be called.T