Kotlin GoogleMaps ClusterManager returns cluster items size smaller than size of items initially passed to it

1k Views Asked by At

I am using a ClusterManager to cluster potentially thousands of markers. The default clustering shows values like 10+, 100+, 500+, etc and I needed to show the exact value.

I therefore overrode getClusterText(bucket: Int): String. When completely zoomed out, the one cluster showing on the map would show 3987 and yet I passed 4000 markers to the cluster manager.

I then thought it had to do with caching or something, so I zoomed in to see if all markers were where they were expected. Lo and behold, it seems that when there are two or more markers on the same spot (same lat and long), and same title and snippet (i'm guessing), only one of them is shown, as if the manager is removing what it thinks are duplicates.

If there are indeed two or more on the spot I would expect it to cluster them, as it is doing in other areas (see image below).

I have verified at the time of passing the markers to the cluster manager that they are indeed 4000 count. But upon zoom out cluster, only 4000-x

What is interesting is that I have an iOS project that consumes the same data, it reports 4000 before adding to the map, and when completely zoomed out, it also shows 4000 and all the expected markers.

enter image description here

As you can see, clustering is working fine. However when there are two of the 'same' markers it doesn't render them. I have checked on all similar instances (same lat, long, etc) and the manager just renders one item.

I have also tried adjusting each ClusterItems position variable by adding a very small random fraction to the lat and long, and also adjust the title and snippet by adding a random string, didn't make a difference.

Is there something I am missing in ClusterManager or elsewhere?

I am unable to post the code at the moment

Update

I have checked my json response and there are indeed two items on that spot with the same data/information (which is required and needs to be shown). Still trying to figure out why it's not clustering them.

enter image description here

2

There are 2 best solutions below

0
On BEST ANSWER

Long story short:

My ClusterItem is actually a subclass of ArrayList<Double> (because of the structure of my json). As a result, clusterManager definitely under the covers ignores duplicates. How it determines that if two ArrayLists (clisterItem for me) seems to be by checking the equality of the contents and not the instances themselves. So if two ArrayLists (ClusterItem for me) have the same contents then they are the same.

Long Story long:

Here is my definition for a clusterItem:

public final class CrimeQueryItem : ArrayList<Double>, ClusterItem{
    //pseudocode here!
    longitude: this[0]
    latitude: this[1]
    position: LatLng(latitude, longitude)
}

By eventually guessing that two CrimeQueryItem are the same if the array that they are have the same contents I decided to override the equals function:

override fun equals(other: Any?): Boolean {
    return this === other
}

This now results in a full instance equality check instead of structural check.

Now the markers are shown as expected:

enter image description here

Now I have no more discrepancies in counts:

enter image description here

Conclusion: I think map checks if it has already added an item, and if so it skips it. In my case two markers where the same if they have the same contents since they are of ArrayList type.

3
On

"However when there are two of the 'same' markers it doesn't render them. I have checked on all similar instances (same lat, long, etc) and the manager just renders one item. "

Probably it does render, but on the same screen position, so we can see it both like single one. So, don't create markers with same coordinates - manually add some "delta" (in pixels, because may be your fraction part for the lat and long is too small) to coordinates of second and other marker. You can use Projection.toScreenLocation() to get screen pixel coordinates of marker, add 5 (pixels) or more to x and y and then use Projection.fromScreenLocation() to get LatLng coordinates of marker.

It may be more complex algorithm - you need to determine quantity of markers with exactly same position and than place them, for example, around "center" of place. Or something like that.