11

In my Android application, I have to delete and re-add a cluster item in my GoogleMap, that represents my current location. But when I run this code:

clusterMng.remove(myitem);

I get this Exception:

java.lang.UnsupportedOperationException: NonHierarchicalDistanceBasedAlgorithm.remove    
not implemented.

Can someone explain to me what this means? Do I have to rewrite some methods of ClusterManager.java in the external library? Or can I simply change my algorithm?

Tarun
  • 13,727
  • 8
  • 42
  • 57
DonaDev
  • 111
  • 1
  • 3

5 Answers5

15

By default ClusterManager uses NonHierarchicalDistanceBasedAlgorithm, that doesn't implement removing elements.

Try to use GridBasedAlgorithm instead (it supports elements remove):

clusterMng.setAlgorithm(new GridBasedAlgorithm<MyClusterItem>());

Or, for better performance, wrap it with PreCachingAlgorithmDecorator, as ClusterManager does by default:

clusterMng.setAlgorithm(new PreCachingAlgorithmDecorator<MyClusterItem>(new GridBasedAlgorithm<MyClusterItem>()));
Serge Populov
  • 1,725
  • 16
  • 19
  • 1
    This is a good solution, but wrapping the algorithm with `PreCachingAlgorithmDecorator` is unnecessary as it automatically does this in the `setAlgorithm()` method. – Jeff Lockhart May 28 '15 at 22:23
8

As @SergePopulov said, NonHierarchicalDistanceBasedAlgorithm does not implement removing elements. For those who dont want to use GridBasedAlgoritm but still needs to remove single elements from NonHierarchicalDistanceBasedAlgorithm there is another solution.

Using this link (Source) you can find source code for the NonHierarchicalDistanceBasedAlgorithm provided by developers in github.

What I did is just save the old Cluster items, clear the clusterManager and add the old items again but do not add the one that is passed through the method.

Firstly create a separate class and paste NonHierarchicalDstanceBasedAlgorithm class code.

public class CustomNonHierarchicalDistanceBasedAlgorithm<MarkerItem extends ClusterItem> implements Algorithm<MarkerItem>
{
    //copy code here
}

After that find method removeItem and replace it with this code:

@Override
public void removeItem(MarkerItem item)
{
    final Collection<QuadItem<MarkerItem>> items = new ArrayList<QuadItem<MarkerItem>>();
    final PointQuadTree<QuadItem<MarkerItem>> quadTree = new PointQuadTree<QuadItem<MarkerItem>>(0, 1, 0, 1);

    for (QuadItem<MarkerItem> temp : mItems)
    {
        if (item.getPosition() != temp.getPosition())
        {
            synchronized (quadTree)
            {
                items.add(temp);
                quadTree.add(temp);
            }
        }
    }

    clearItems();

    for (QuadItem<MarkerItem> temp : items)
    {
        synchronized (mQuadTree)
        {
            mItems.add(temp);
            mQuadTree.add(temp);
        }
    }
}

After that go where your ClusterManager is created and paste code below containing your class name:

clusterManager.setAlgorithm(new CustomNonHierarchicalDistanceBasedAlgorithm<MarkerItem>());

Where your MarkerItem is your class which implemented ClusterItem. And it should now work.

Don't forget to recluster your ClusterManager after you remove the item by running:

clusterManager.cluster();
  • I am getting MarkerItems cannot be resolved to a type error message –  Jan 02 '15 at 11:28
8

Here is how I did it:

@Override
public void removeItem(T item) {
    final QuadItem<T> quadItem = new QuadItem<T>(item);
    synchronized (mQuadTree) {
        mItems.remove(quadItem);
        mQuadTree.remove(quadItem);
    }
}

I also implemented equals() and hashCode() in QuadItem as it is recommended in the TODO of the NonHierarchicalDistanceBasedAlgorithm source code:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof QuadItem)) {
        return false;
    }

    QuadItem quadItem = (QuadItem) o;

    return mClusterItem.equals(quadItem.mClusterItem);

}

@Override
public int hashCode() {
    return mClusterItem.hashCode();
}

Finally, I implemented equals() and hashCode() in my ClusterItem's descendant class.

Viachaslau Tysianchuk
  • 1,680
  • 19
  • 22
  • confirmed, that this solution works! Performance wise it seems good. Can handle over 1k markers – Gibberish May 28 '15 at 11:52
  • @Viachaslau Tysianchuk , how did you managed to modify the NonHierarchicalDistanceBasedAlgorithm.QuadItem to implements those methods? Did you have to use the library as a module? – desgraci Jul 02 '15 at 17:26
  • 1
    @desgraci I've copied the full source code of android-maps-utils into my project because I needed to make several other changes. For this case copying just the NonHierarchicalDistanceBasedAlgorithm could be enough. – Viachaslau Tysianchuk Jul 03 '15 at 20:10
  • This isn't working for me. I downloaded the NonHierarchical class and changed removeItem method, and implemented the equals & hashcode methods. Then, in my 'CustomItem extends ClusterItem' class i just overrode equals & hashcode. Any suggestions? Thank you! – xsorifc28 Oct 02 '15 at 01:53
  • @xsorifc28 Can't suggest much without looking at your code. Maybe check if your implementation of hashCode() follows the rules from http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29. Wrong implementation of hashCode() could cause bugs while working with hashmaps and hashsets. – Viachaslau Tysianchuk Oct 03 '15 at 15:31
  • I'm getting java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.List.remove(java.lang.Object)' on a null object reference custom_classes.CustomNonHierarchicalDistanceBasedAlgorithm.removeItem(CustomNonHierarchicalDistanceBasedAlgorithm.java:74) BUT mItems cannot be null??? EDIT: Ah that was because I called clearItems before removeItem. BUT now I get ConcurrentModificationException... – Denny Weinberg Aug 01 '16 at 16:37
1

After updating android-maps-utils to 0.5

clusterManager.remove(item); will never throw an UnsupportedOperationException("NonHierarchicalDistanceBasedAlgorithm.remove not implemented")

Refer this thread

sivaBE35
  • 1,876
  • 18
  • 23
0

I have found removeItem(T item) in the source code of ClusterManager.java Tested, it works Link to source code https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/clustering/ClusterManager.java

kashlo
  • 2,313
  • 1
  • 28
  • 39