I have to implement in my app clustering functionality for data loaded from server. I have successfully showed the data in the map using retrofit library, but I tried to do clustering and it is not working. I followed the android docs and some tutorials on internet but I'm very confused of what I'm doing wrong. Here is my code:
Callback<List<Vehicle>> callback = new Callback<List<Vehicle>>() {
@Override
public void onResponse(@NotNull Call<List<Vehicle>> call, Response<List<Vehicle>> response) {
if (response.isSuccessful()) {
vehicles = response.body();
assert vehicles != null;
try {
mGoogleMap.clear();
for (int i = 0; i < vehicles.size(); i++) {
PortalMetaData metaData = vehicles.get(i).getPortalMetaData();
float x = metaData.getLocations().getX();
float y = metaData.getLocations().getY();
float offset = i / 60f;
x = x + offset;
y = y + offset;
MarkerOptions markerOptions = new MarkerOptions();
LatLng latLng = new LatLng(x, y);
markerOptions.position(latLng);
markerOptions.title(metaData.getPortalName());
markerOptions.snippet("Id: " + vehicles.get(i).getId());
mGoogleMap.addMarker(markerOptions);
cameraConfigurations(latLng);
mClusterManager = new ClusterManager<>(getApplicationContext(), mGoogleMap);
ClusterItem location = new ClusterItem(x, y);
mClusterManager.addItem(location);
CustomClusterRenderer renderer = new CustomClusterRenderer(getApplicationContext(), mGoogleMap, mClusterManager);
//mClusterManager.setAlgorithm(new NonHierarchicalDistanceBasedAlgorithm<>());
mClusterManager.setRenderer(renderer);
mClusterManager.cluster();
mGoogleMap.setOnCameraIdleListener(mClusterManager);
mGoogleMap.setOnMarkerClickListener(mClusterManager);
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 5.0f));
}
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
} else {
System.out.println(response.body());
Log.e(TAG, "Error: data cannot be loaded");
}
I'm debugged and everything seems to be fine. and my custom renderer is like that:
private static final int MIN_CLUSTER_SIZE = 1;
private final IconGenerator mClusterIconGenerator;
private Context mContext;
private ClusterManager<ClusterItem> mClusterManager;
Map<Cluster<ClusterItem>, Marker> clusterMarkerMap = new HashMap<>();
public CustomClusterRenderer(Context context, GoogleMap map, ClusterManager<ClusterItem> clusterManager) {
super(context, map, clusterManager);
mContext = context;
mClusterManager = clusterManager;
mClusterIconGenerator = new IconGenerator(context);
}
@Override
protected void onBeforeClusterItemRendered(@NonNull ClusterItem item, @NonNull MarkerOptions markerOptions) {
BitmapDescriptor mBitmapDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);
markerOptions.icon(mBitmapDescriptor);
}
@Override
protected void onClusterItemRendered(@NonNull ClusterItem clusterItem, @NonNull Marker marker) {
super.onClusterItemRendered(clusterItem, marker);
}
@SuppressLint("UseCompatLoadingForDrawables")
@Override
protected void onBeforeClusterRendered(@NonNull Cluster<ClusterItem> cluster, @NonNull MarkerOptions markerOptions) {
final Drawable mClusterIcon = mContext.getResources().getDrawable(ic_baseline_directions_car_24);
mClusterIcon.setColorFilter(mContext.getResources().getColor(android.R.color.holo_orange_light), PorterDuff.Mode.SRC_ATOP);
mClusterIconGenerator.setBackground(mClusterIcon);
if (cluster.getSize() > MIN_CLUSTER_SIZE) {
mClusterIconGenerator.setContentPadding(40, 20, 0, 0);
} else {
mClusterIconGenerator.setContentPadding(30, 20, 0, 0);
}
Bitmap mIcon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(mIcon));
}
@Override
protected boolean shouldRenderAsCluster(@NonNull Cluster<ClusterItem> cluster) {
return cluster.getSize() > MIN_CLUSTER_SIZE;
}
@Override
protected void onClusterRendered(@NonNull Cluster<ClusterItem> cluster, @NonNull Marker marker) {
super.onClusterRendered(cluster, marker);
clusterMarkerMap.put(cluster, marker);
}
Could someone please give me some suggestions of what I'm doing wrong or what could be a good aproach to set clustering correctly.
EDIT: Finally I solved my problem, it was a mistake I was doing. I was adding to cluster manager only one cluster item. I created a new ArrayList of cluster items and in the for loop I added coordinates for each items. Then outside the for loop I called clustermanager.addItems(clusteritems) and is working. Below is my code for anyone facing this issue:
Callback<List<Vehicle>> callback = new Callback<List<Vehicle>>() {
@Override
public void onResponse(@NotNull Call<List<Vehicle>> call, Response<List<Vehicle>> response) {
if (response.isSuccessful()) {
vehicles = response.body();
assert vehicles != null;
List<ClusterItem> clusterItems = new ArrayList<>();
try {
mGoogleMap.clear();
for (int i = 0; i < vehicles.size(); i++) {
PortalMetaData metaData = vehicles.get(i).getPortalMetaData();
float x = metaData.getLocations().getX();
float y = metaData.getLocations().getY();
float offset = i / 60f;
x = x + offset;
y = y + offset;
MarkerOptions markerOptions = new MarkerOptions();
LatLng latLng = new LatLng(x, y);
markerOptions.position(latLng);
markerOptions.title(metaData.getPortalName());
markerOptions.snippet("Id: " + vehicles.get(i).getId());
mGoogleMap.addMarker(markerOptions);
cameraConfigurations(latLng);
mClusterManager = new ClusterManager<>(getApplicationContext(), mGoogleMap);
ClusterItem location = new ClusterItem(x, y);
mClusterManager.addItem(location);
clusterItems.add(location);
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 5.0f));
}
CustomClusterRenderer renderer = new CustomClusterRenderer(getApplicationContext(), mGoogleMap, mClusterManager);
mClusterManager.addItems(clusterItems);
mClusterManager.setAlgorithm(new NonHierarchicalDistanceBasedAlgorithm<>());
mClusterManager.setRenderer(renderer);
mClusterManager.cluster();
mGoogleMap.setOnCameraIdleListener(mClusterManager);
mGoogleMap.setOnMarkerClickListener(mClusterManager);
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
} else {
System.out.println(response.body());
Log.e(TAG, "Error: data cannot be loaded");
}