Android — ошибка кластеризации карты Google с маркерами, которые не были повторно кластеризованы

#android #google-maps #google-maps-markers #markerclusterer

#Android #google-карты #google-карты-маркеры #markerclusterer

Вопрос:

Редактировать: показать, что mapManager.filter() делает метод.

У меня есть приложение для Android с ~ 20 тыс. маркеров, которые рисуются на карте, и с опцией фильтров, поэтому маркеры рисуются и удаляются много. В настоящее время я использую эту библиотеку кластеризации, потому что она более эффективна для отображения большого количества маркеров, чем классическая библиотека карт Google. Но он не поддерживается и не обновлялся с 3 лет, и я не нашел никаких альтернатив.

Вот видео с ошибкой.

Вот мой код, который вызывается, когда я нажимаю на опцию фильтрации в своем приложении:

  private void filter(){
    
    //currentMapManager contain all the filters option and also the array list
    //of the unfiltered markers (~20,000 markers)
    //it's filter method retrieve the current filtering option enable (marker type, and other specs)
    //And return markers from the full arraylist that match those filters options.

    ArrayList<MarkerModel> filteredList = currentMapManager.filter(currentMapManager.getAllMarkers());

    if (clusterManager != null) {
        clusterManager.setItems(new ArrayList<>());
        clusterManager.onCameraIdle();
        clusterManager.setItems(filteredList);
        clusterManager.onCameraIdle();
    }
  

Вот mapManager.filter() метод.

 public ArrayList<MarkerModel> filter(List<MarkerModel> currentMarkers) {
    ArrayList<Object> filtersArray = filters.getFilters();
    /* filtersArray is an array like this : 
    * ['type', ['typeFilter1', 'typeFilter2'], 
    * 'date', dateTimestamp, 
    * 'withPictures', true, 
    * ....] 
    */
    return filter(currentMarkers, filtersArray);
}

private ArrayList<MarkerModel> filter(List<MarkerModel> currentMarkers, 
                                      ArrayList<Object> fieldsAndValues) {
  
    if (fieldsAndValues.size() % 2 == 1) {
        throw new IllegalArgumentException("Missing value in call to filterList().  
        There must be an even number of arguments that alternate between 
        field names and values");
    } else {
        //Here the arraylist that we are returning
        ArrayList<MarkerModel> filteredMarkers = new ArrayList<>();

        List<Object> argumentList = new ArrayList();
        Collections.addAll(argumentList, fieldsAndValues);

        if (!currentMarkers.isEmpty()) {
            for (int j = 0; j < currentMarkers.size(); j  ) {
                MarkerModel marker = currentMarkers.get(j);
                boolean isInFilter = true;
                //Check fieldsAndValue filters...
                //If isInFilter stay to true we 
                
                filteredMarkers.add(marker);
            }
        }
        return filteredMarkers;
    }
}
  

Я думаю, проблема в том, что библиотека кластеров не должна так сильно перерисовываться, и в какой-то момент она перестала читать и работать с массивом элементов 20k.
Я просмотрел всю ветку forks этой библиотеки и посмотрел / попытался понять исходный код библиотеки, но не нашел никакого решения моей проблемы…

Если вам нужна другая часть моего исходного кода, чтобы понять больше, скажите мне, я добавлю ее.

Большое спасибо, если вы можете мне помочь, я много боролся с этой проблемой…

Комментарии:

1. Одна вещь, которую я замечаю в реализации библиотеки setItems , заключается в том, что она пытается отменить любой активный mQuadTreeTask , но не ждет onCancelled (вероятно, потому, что это усложняет реализацию). Однако при быстром увеличении / уменьшении масштаба это может выявить проблему, поскольку каждая нерешенная задача работает с одним и тем же квадродеревом. Подробнее об cancel этом здесь: developer.android.com/reference/android/os /.

2. С учетом сказанного, похоже, что он использует однопоточный исполнитель, что означает, что вышеупомянутое не будет применяться, поскольку может быть запущена только одна задача — все еще неправильная реализация, хотя — тем более, что вы не знаете, когда setItems на самом деле завершено (с точки зрения клиента) — например, что, если вы измените filteredList — делаетверните currentMapManager.filter клон или новый список (обратите внимание, что инициализация filteredList в опубликованном выше коде ничего не делает), поскольку вы просто перезаписываете.

3. Просто имейте в виду в своем коде: когда вы вызываете setItems , и он возвращает, это на самом деле не выполняется из-за реализации asynctask — это действительно должно обеспечить «полный обратный вызов».

4. Спасибо, Энди! Я собираюсь попытаться реализовать это onComplete с помощью a listener и сообщу вам, решит ли это проблему или нет. Для инициализации filteredList это потому, что у меня есть больше кода с некоторыми if / else для моих параметров глобальной фильтрации (и не связанных с currentMapManager ), но я удалил много строк для упрощения здесь. currentMapManager.filter верните новый список, который я отредактировал в своем вопросе, чтобы немного показать, что он делает (снова упрощенный)

5. Может оказаться трудным ввести обратный вызов, поскольку mQuadTreeTask по завершении появляется вторая задача ( ClusterTask ) для инициирования обновления кластеризации. Также обратите внимание, что onCameraIdle инициирует a ClusterTask , что означает, что вы setItems инициируете кластеризацию, за которой немедленно следует вторая кластеризация onCameraIdle . Я бы рекомендовал создать простой проект карты с маркерами 100k и различными «отфильтрованными» случаями, используя ваш код и наблюдая за результатами — я могу сделать это сам и опубликовать результаты. Также добавьте краткое объяснение видео относительно того, что вы считаете неправильным — для ясности.