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