Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClusterManager repaint markers of Google maps v2 utils

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);
like image 824
PaNaVTEC Avatar asked Mar 09 '14 19:03

PaNaVTEC


4 Answers

mClusterManager.cluster();

force re-clustering items when you after added new item.

like image 190
Oscar Kuok Avatar answered Oct 23 '22 16:10

Oscar Kuok


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 :)

like image 26
PaNaVTEC Avatar answered Oct 23 '22 16:10

PaNaVTEC


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.

like image 3
user3687289 Avatar answered Oct 23 '22 16:10

user3687289


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());
    }

}
like image 3
John Langone Avatar answered Oct 23 '22 16:10

John Langone