Android - google 地图卡住了

Android - google maps gets stuck

我正在开发一个显示 Google 地图和上面一堆标记的应用程序。有很多标记,所以我将它们分成较小的组并仅显示那些在一定范围内的标记,具体取决于相机的当前位置。

为此,我使用 GoogleMap.OnCameraIdleListener。首先,我删除监听器,进行计算和绘图,然后将监听器恢复到包含我的地图的片段:

@Override
public void onCameraIdle() {
    mMap.setOnCameraIdleListener(null);

    clearMap();
    findTheMarkersInBounds();
    displayTheMarkers();

    mMap.setOnCameraIdleListener(this);
}

这样我只绘制了我需要显示的标记,而且性能比一次在地图上有 1000 个标记要好得多。我也画了大约相同数量的多段线,但现在这不是重点。

由于一些奇怪的原因,在平移和缩放地图后不再响应。不能缩放也不能平移。应用程序显示一个对话框,表明它没有响应,我应该等待或关闭该应用程序。 logcat 中没有显示错误。我不能确切地说出这种情况何时发生。有时在第一次平底锅后,有时我可以移动 2-3 分钟左右。同样的事情发生在模拟器和物理设备上。

有人经历过这样的事情吗?谢谢! 还是我以错误的方式接近这个?我还应该如何优化地图以显示大约 1000 个标记和折线。 (标记上有文字,所以它不能是同一个位图,所有的多段线可以有不同的颜色并且需要可点击,所以我不能将它们组合成一条大多段线)

编辑。关于我的方法的更多信息:

从内部数据库加载所有标记位置后,我对所有标记位置进行for循环,并根据它们的位置将它们放置到相应的区域。它是一个二维列表数组。

我的整个区域被分成了 32x32 个较小的矩形区域。当我搜索要显示的标记时,我确定哪个区域在视图中并仅显示该区域中的那些标记。 这样我就不需要遍历所有标记了。

我的方法(非常简单)如下所示:

ArrayList<MarkerObject> markersToDisplay = new ArrayList<MarkerObject>();

private void findTheMarkersInBounds() {
    markersToDisplay.clear();
    LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
    int[] regionCoordinates = getRegionCoordinates(bounds); // i, j coordinates of my regions [0..31][0..31]
    markersToDisplay.addAll(subdividedMarkers[regionCoordinates[0]][regionCoordinates[1]]);
}

private void drawMarkers() {
    if ((markersToDisplay != null) && (markersToDisplay.size() > 0)) {
        for (int i=0; i<markersToDisplay.size(); i++) {
            MarkerObject mo = markersToDisplay.get(i);
            LatLng position = new LatLng(mo.gpsLat, mo.gpsLon);
            BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title));
            GroundOverlay m = mMap.addGroundOverlay(groundOverlayOptions.image(bitmapDescriptor).position(position, 75));
            m.setClickable(true);
        }
    }
}

如果没有 findTheMarkersInBounds()displayTheMarkers() 的源代码,很难对您有所帮助,但是看来,您需要不同的方法来提高性能,例如:

  1. 尽可能改进您的 findTheMarkersInBounds() 逻辑;

  2. 运行findTheMarkersInBounds() 在单独的线程中并且不是同时显示所有标记,而是在 findTheMarkersInBounds() 搜索;

  3. 如果可能的话,改进你的 displayTheMarkers(),实际上可以在 canvas 上使用自定义绘图(如 答案)而不是创建数千 Marker 个对象。

问题更新:

小改进(首先,因为它们用于 main):

  1. 将大约 markersToDisplay 的最大大小作为构造函数参数传递: ArrayList<MarkerObject> markersToDisplay = new ArrayList<MarkerObject>(1000);

  2. 改为for (int i=0; i<markersToDisplay.size(); i++) {

使用for (MarkerObject mo: markersToDisplay) {

  1. 不要每次都创建LatLng position,创建一次并存储在MarkerObject个字段中。

主要改进:

这几行是问题的根源:

BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title));
GroundOverlay m = mMap.addGroundOverlay(groundOverlayOptions.image(bitmapDescriptor).position(position, 75));

恕我直言,使用地面叠加层显示数千个标记是个坏主意。 Ground Overlay 用于多个“用户”地图,显示默认 Google 地图(如公园或动物园详细信息的本地计划)。在 canvas 上使用自定义绘图,就像在上面的 link 上一样。但是,如果您决定使用地面叠加层 - 不要每次都重新创建它们:创建一次,将对它们的引用存储在 MarkerObject 中并重复使用:

// once when marker created (just example)
mo.overlayOptions = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title)))
.position(mo.position, 75))
.setClickable(true);

...
// in your drawMarkers() - just add:
... 
for (MarkerObject mo: markersToDisplay) {
    if (mo.overlayOptions == null) {
        mo.overlayOptions = createOverlayOptionsForThisMarker();
    }
    mMap.addGroundOverlay(mo.overlayOptions)
}

但是恕我直言 - 完全摆脱成千上万的地面覆盖 - 在 canvas 上使用自定义绘图。

在进一步调查并与 google 地图 android 技术支持人员沟通后,我们找到了解决方案。 GroundOverlay.setZIndex() 方法中存在错误。

您所要做的就是更新到最新的API版本。 Google Maps SDK v3.1 中不再存在此错误。

目前它处于 Beta 阶段,但迁移非常简单。