android android-maps-v2 android-maps-utils

android - ClusterManager vuelve a pintar los marcadores de Google Maps v2 utils



android-maps-v2 android-maps-utils (7)

Hola, estoy haciendo una solicitud de servidor y cuando recibí la solicitud del servidor, estoy ejecutando en Ui Thread a ClusterManager.addItem () pero estos elementos no se pintan en el mapa, solo cuando hago una actualización de zoom (+, -) están mostrando Además, traté de depurar el renderizador, pero no se llama onBeforeClusterRendered / onBeforeClusterItemRendered hasta que actualizo el zoom en el mapa. ¿Alguna idea de cómo actualizar el mapa / clusterManager / marcadores?

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


Estaba teniendo el mismo problema exacto. Ninguna de las soluciones sugeridas funcionaba para mí. Hice una clase que extiende el DefaultClusterRenderer y agrega el método público updateClusterItem (ClusterItem clusterItem) que forzará que el Marker asociado con ese ClusterItem se vuelva a representar (funciona tanto con clusters como con elementos de cluster).

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


Mi solución con un CustomRenderer que extiende DefaultClusterRenderer

protected void onClusterItemRendered(T clusterItem, Marker marker) { marker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); }


Parece que encontré una solución.

ClusterManager usa un procesador, en este caso, hereda de DefaultClusterRenderer, que usa un caché interno, un caché de marcadores que se agregan al mapa. Puede acceder directamente a los marcadores agregados en el mapa, no uso la ventana de información, por lo que agrego un marcador options.title () un ID para luego encontrar este marcador, así que:

@Override protected void onBeforeClusterItemRendered(TweetClusterItem item, MarkerOptions markerOptions) { .... Blabla code.... markerOptions.title(Long.toString(tweet.getId())); .... Blabla code.... }

y cuando quiero recargar el clusterItem, llamo a este método:

/** * 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; } } }

Tal vez sea un poco hacky pero funciona y no encontré ninguna otra forma de hacer esto. Si encontraste otra forma mejor, por favor comparte :)


Puede obtener marcadores específicos que correspondan a su clúster o elementos de clúster y viceversa en O (1) mediante el uso de DefaultClusterRenderer getMarker (), getCluster () y getClusterItem () (configure su propio procesador para acceder al objeto de renderizador).

Use estos métodos para cambiar los marcadores de sus artículos cuando lo necesite.

... DefaultClusterRenderer mRenderer = ... mClusterManager.setRenderer(mRenderer); ... public void reloadMarker(ClusterItem item) { mRenderer.getMarker(item).setIcon(YOUR_ICON); }

Sin embargo, no recomendaría guardarlos en ningún otro lugar, ya que esos métodos devuelven los objetos de caché del renderizador.


Yo tuve el mismo problema. También se vio agravado por el hecho de que estoy haciendo una representación personalizada en onBeforeClusterItemRendered en mi subclase DefaultClusterRenderer.

Mi solución fue crear una nueva instancia de mi subclase DefaultClusterRenderer y llamar a setRenderer en el ClusterManager nuevamente. Esto vuelca todos los iconos almacenados en caché y recrea todo.

Es intrépido, fuerza bruta y molesto ineficiente, pero funciona. Fue el único enfoque que encontré que funcionó ya que la biblioteca parece no tener un apoyo explícito para esto.


mClusterManager.cluster ();

forzar la reagrupación de elementos cuando se agrega un nuevo elemento.


mClusterManager.cluster(); no funcionó para mí

esto hizo sin embargo:

if (mMap != null) { CameraPosition currentCameraPosition = mMap.getCameraPosition(); mMap.moveCamera(CameraUpdateFactory.newCameraPosition(currentCameraPosition)); }

Esto provocó una llamada a onCameraChange, donde ya estaba haciendo mClusterManager.clearItems () ... mClusterManager.addItem (..) - para objetos dentro de la región visible ... mClusterManager.cluster ()

Para mí, el contexto fue que los pines estaban desapareciendo cuando regresaba al fragmento que mostraba el mapa (- solo en ciertos dispositivos, por ejemplo, Nexus 7, donde no había una llamada automática a OnCameraChange)