こんにちは私はサーバーリクエストを行っています。サーバーからリクエストを受け取ったとき、UiスレッドでClusterManager.addItem()を実行していますが、ズームを更新した場合にのみ、このアイテムはマップにペイントされません(+、-)表示されています。また、レンダラーをデバッグしようとしましたが、ズームインマップを更新するまでonBeforeClusterRendered/onBeforeClusterItemRenderedが呼び出されません。 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);
回避策を見つけたようです。
ClusterManagerはレンダラーを使用します。この場合、内部キャッシュ、つまりマップに追加されるマーカーのキャッシュを使用するDefaultClusterRendererから継承します。地図に追加されたマーカーに直接アクセスできます。情報ウィンドウは使用しないので、後でこのマーカーを見つけるために、マーカーのoptions.title()にIDを追加します。
@Override
protected void onBeforeClusterItemRendered(TweetClusterItem item, MarkerOptions markerOptions) {
.... Blabla code....
markerOptions.title(Long.toString(Tweet.getId()));
.... Blabla code....
}
clusterItemをリロードするときは、次のメソッドを呼び出します。
/**
* 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;
}
}
}
多分少しハックですが、それはうまくいき、私はこれを行う他の方法を見つけることができません。別のより良い方法を見つけた場合は、共有してください:)
mClusterManager.cluster();
新しいアイテムを追加した後、アイテムを強制的に再クラスタリングします。
私はまったく同じ問題を抱えていました。提案された解決策のどれも私のために働いていませんでした。 DefaultClusterRendererを拡張し、パブリックメソッドupdateClusterItem(ClusterItem clusterItem)を追加するクラスを作成しました。これにより、そのClusterItemに関連付けられたマーカーが強制的に再レンダリングされます(クラスターとクラスターアイテムの両方で機能します)。
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());
}
}
mClusterManager.cluster();
が機能しませんでした
これはしかししました:
if (mMap != null) {
CameraPosition currentCameraPosition = mMap.getCameraPosition();
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(currentCameraPosition));
}
これにより、onCameraChange呼び出しがトリガーされました。ここでは、すでにmClusterManager.clearItems()... mClusterManager.addItem(..)を実行していました-可視領域内のオブジェクトに対して... mClusterManager.cluster()
私のコンテキストは、マップを表示しているフラグメントに戻るとピンが消えていたということでした(-OnCameraChangeへの自動呼び出しがなかったNexus 7などの特定のデバイスのみ)。
DefaultClusterRendererのgetMarker()、getCluster()、およびgetClusterItem()を使用して、O(1)で、クラスターまたはクラスターアイテムに対応する特定のマーカーを取得できます。レンダラーオブジェクト)。
これらの方法を使用して、必要なときにいつでもアイテムのマーカーを変更できます。
...
DefaultClusterRenderer mRenderer = ...
mClusterManager.setRenderer(mRenderer);
...
public void reloadMarker(ClusterItem item) {
mRenderer.getMarker(item).setIcon(YOUR_ICON);
}
ただし、これらのメソッドはレンダラーのキャッシュオブジェクトを返すため、他の場所に保存することはお勧めしません。
私も同じ問題を抱えていました。また、DefaultClusterRendererサブクラスのonBeforeClusterItemRenderedでカスタムレンダリングを行っているという事実によってさらに複雑になりました。
私の解決策は、DefaultClusterRendererサブクラスの新しいインスタンスを作成し、ClusterManagerでsetRendererを再度呼び出すことでした。これにより、キャッシュされたすべてのアイコンがダンプされ、すべてが再作成されます。
ハックで力ずくで面倒なほど非効率的ですが、機能します。ライブラリがこれを明示的にサポートしていないようであるため、これが機能することがわかった唯一のアプローチでした。
マーカーはズームインまたはズームアウト時にのみ表示されることに気づいたので、わずかなズームの変更を除いて、すべての古い値で新しいカメラ位置を設定しました。
CameraPosition currentCameraPosition = googleMap.getCameraPosition();
CameraPosition cameraPosition = new CameraPosition(currentCameraPosition.target, currentCameraPosition.zoom - .1f, currentCameraPosition.tilt, currentCameraPosition.bearing);
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));