Проблема с удалением элемента из кластера

В моем приложении для Android я должен удалить и повторно добавить элемент кластера в свой GoogleMap, который представляет мое текущее местоположение. Но когда я запускаю этот код:

clusterMng.remove(myitem);

Я получаю это исключение:

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

Может кто-нибудь объяснить мне, что это значит? Должен ли я переписать некоторые методы ClusterManager.java во внешней библиотеке? Или я могу просто изменить свой алгоритм?

Ответ 1

По умолчанию ClusterManager использует NonHierarchicalDistanceBasedAlgorithm, который не реализует удаление элементов.

Попробуйте вместо этого использовать GridBasedAlgorithm (он поддерживает удаление элементов):

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

Или, для лучшей производительности, оберните его с помощью PreCachingAlgorithmDecorator, как это делает ClusterManager по умолчанию:

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

Ответ 2

Как сказал @SergePopulov, NonHierarchicalDistanceBasedAlgorithm не реализует удаление элементов. Для тех, кто не хочет использовать GridBasedAlgoritm, но все же необходимо удалить отдельные элементы из NonHierarchicalDistanceBasedAlgorithm, есть еще одно решение.

Используя эту ссылку (Источник), вы можете найти исходный код для алгоритма NonHierarchicalDistanceBasedAlgorithm, предоставленного разработчиками в github.

То, что я сделал, это просто сохранить старые элементы кластера, очистить кластерManager и снова добавить старые элементы, но не добавлять тот, который передается через этот метод.

Сначала создайте отдельный класс и вставьте код класса NonHierarchicalDstanceBasedAlgorithm.

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

После этого найдите метод removeItem и замените его на этот код:

@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);
        }
    }
}

После этого создайте свой ClusterManager и вставьте код ниже, содержащий имя вашего класса:

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

Где ваш MarkerItem - ваш класс, который реализовал ClusterItem. И теперь он должен работать.

Не забудьте повторно открыть ClusterManager после удаления элемента, выполнив:

clusterManager.cluster();

Ответ 3

Вот как я это сделал:

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

Я также реализовал equals() и hashCode() в QuadItem, как это рекомендуется в TODO исходного кода NonHierarchicalDistanceBasedAlgorithm:

@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();
}

Наконец, я реализовал equals() и hashCode() в классе ClusterItem потомков.