【问题标题】:Polylines performance issues on GoogleMaps API v2GoogleMaps API v2 上的折线性能问题
【发布时间】:2014-07-19 03:53:06
【问题描述】:

我正在为 android 编写一个应用程序,我必须在其中表示某些块外观。为此,我为每个相关的块立面绘制了一条折线(非常简单的折线,实际上是 2 条点线......)。

最坏的情况,可能有多达 100k 多段线。

我的问题是我正在运行大约 3000 行的测试,而且它已经很慢了。让数据显示没有问题,画线也没有问题,但是当绘制超过 1k 条线时,地图会变得迟钝。

我为每条折线创建一个 PolylineOptions,然后将其绘制并存储在一个变量中,如下所示:

PolylineOptions options = new PolylineOptions();
options.add(latlon1, latlon2);
options.width(5);
options.color(Color.RED);
Polyline myPolyline = map.addPolyline(options);
myPolyline.setVisible(true);
myPolylines.add(myPolyline);

我尝试不存储它们(尽管这对于以后的处理是必要的)以防它是一个内存问题,但没有产生任何影响......此外,在存储它们时,应用程序的其余部分可以流畅地运行(有些额外的按钮/文本字段),只是地图变慢(移动/缩放时)。

哦,我正在使用 google maps api v2 的 mapfragment 类。

所以,问题是:有什么方法可以提高地图性能?

提前致谢。

编辑:多段线一次全部可见。为了避免绘制不必要的线条,我添加了一个“上一步”,在该步骤中,我绘制了代表具有填充颜色(绿色到红色)的立面数量的圆圈,并且仅在选择了一个圆圈并且用户要求提供详细视图时才显示线条.

EDIT2:这是我想要完成的(它来自地图指南,但我正在尝试在 android 上复制)

【问题讨论】:

  • 所有折线是否一次可见?如果没有,只需绘制地图区域中可见的线条即可。
  • 是的,多段线一次全部可见。我什至添加了一个“上一步”,其中我绘制了代表具有填充颜色(绿色到红色)的外墙数量的圆圈,并且仅在选择了一个圆圈并且用户要求详细视图时显示线条。
  • 你需要做集群

标签: android google-maps google-maps-android-api-2 android-maps-v2 mapfragment


【解决方案1】:

如果折线没有变化,我会将它们绘制在背景图块上,而不是使用地图折线功能。

有关如何将基于 LatLng-Coordinates 的形状绘制到图块中的示例,请参阅我对this SO question的回答

【讨论】:

  • 非常感谢,效率更高了。我在内存填满时遇到了一些错误,并且随机地,图块没有显示出来,但这可能是我的编码,因为我刚刚尝试过,我会再测试一下。再次感谢。
  • 你必须非常小心线程安全。瓷砖同时在许多线程中创建。有些瓷砖没有出现,可能指向这个方向。
  • 一开始我创建了太多的提供者(因为数据是按组划分的,我为每个组创建了一个提供者)我现在又回到了一次在图块上绘制所有内容,到目前为止没有问题,它非常顺利。我现在要重写我的 ontap,因为覆盖似乎阻止了它。再次感谢,您的代码很有帮助。
  • 别管ontap,这是我这边的一个混合版本,它不会阻止触摸事件。谢谢。
  • @Chess 如果可能的话,你能分享一下结果代码吗?
【解决方案2】:

不要一次绘制所有的东西,只绘制你能看到的东西。

所以你会得到可见地图的边界

VisibleRegion vr = map.getProjection().getVisibleRegion();
bounds = vr.latLngBounds;

然后检查你的线是否在可见区域的范围内,然后绘制线

这样做将允许您在异步任务中运行代码,您可以在其中使用处理程序回调主线程以在需要时绘制一条线。

您还必须覆盖 onCameraChange 才能知道 VisibleRegion 何时更改。你模式的地图。您还必须使用此方法执行其他操作,例如跟踪是否绘制了一条线,这样您就不会多次绘制同一条线

【讨论】:

  • 遗憾的是,这些线条一次都可见。在我的测试数据集中,行的最小相关部分约为 500,在最坏的情况下可能约为 10,000。此外,可能有理由分析更大的区域,因此我的测试集上需要大约 3000 行,而在危机中需要大约 50,000 行......
  • 是的,这就是为什么你会看到滞后,只绘制在那个时间点可见的东西,它会更快
  • 但是它们都是可见的,并且需要......即使绘制数据集的非常(相对)小部分(7000 个中的 1000 个)它也会滞后。感谢您的回复!
  • 不,他们不需要,当地图移动时,您检查是否有需要绘制的新线。你 100% 不需要绘制每一行
  • 好的,所以看看图片我明白你的意思,实际上你最好的选择是将它变成图片并使用Tile Overlay,因为没有办法防止 UI 滞后. developers.google.com/maps/documentation/android/tileoverlay 可能会尝试从更高的缩放级别开始,而不是一次显示所有内容,而是在用户放大时显示更多
【解决方案3】:

我正在使用异步任务创建折线选项,每个坐标有 50 个坐标,并在发布进度方法中将折线添加到地图中。如果它运行的时间过长并且没有运行,我仍然有一个进度对话框,用户可以使用后退按钮取消任务。我最大的测试是来自 sqllite 数据库的 3000 个坐标。但是,如果每个折线选项有两个坐标,则此代码会在调用 publishprogress 时陷入困境,因此您必须堆叠几十条两条坐标折线,然后在 publishprogress 方法中将它们添加到地图中。 PublishProgress 采用一个数组,因此传入 50 个折线选项并不难。在使用每条折线 50 个坐标进行调试时,您可以看到在地图上绘制的折线。在实时模式下,折线仅在一秒钟内出现在我便宜的 50 美元测试手机上。

注意:我将所有异步任务作为单独的 .java 文件执行,因此我可以在构造函数中传递我需要的任何内容,因此我有相同的 cancelMe() 代码。我使用的大部分代码都在下面,我省略了数据库的内容,因为每个人都会有所不同。

public class TaskParseKmldb extends AsyncTask<KmlSummary, PolylineOptions, Boolean>
        implements OnCancelListener {

public interface TaskParseKmldbCallback {
    void onTaskParseKmldbComplete(boolean success);
}


public TaskParseKmldb(Activity activity, KmlSummary kmlSummary, GoogleMap mMap,
            ProgressDialog pd) {
    this.activity = activity;
    this.kmlSummary = kmlSummary;
    this.mMap = mMap;
    this.pd = pd;
    // determine if calling activity has implemented the callback interface
    callback = (TaskParseKmldbCallback.class.isAssignableFrom(activity
.getClass())) ? (TaskParseKmldbCallback) activity : null;   
    }

... 为 onCanceled 例程设置进程对话框侦听器。

@Override
    protected void onPreExecute() {
        pd.setOnCancelListener(this);
        pd.setMessage("Loading Recorded Route...");
        pd.show();
    }


@Override
protected void onCancelled(Boolean result) {
    if (pd != null) {
        pd.dismiss();
        pd = null;
    }
    if (callback != null) {
        callback.onTaskParseKmldbComplete(result);
    }
}

@Override
    public void onCancel(DialogInterface dialog) {
        cancelMe(); // this just gracefully cancels the task.
    }

public void cancelMe() {
    if (!getStatus().equals(Status.FINISHED)) {
        // not canceled
        if (!isCancelled()) {
            cancel(false);
            try {
                get();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (CancellationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

... doInBackground 中的某处

if (progress.getPoints().size() > 0) {
                publishProgress(progress);
                ret = true;
            }


protected void onProgressUpdate(PolylineOptions... progress) {
        if (isCancelled()) {
            return;
        }
        if (progress[0] != null) {
            // add the poly line to the map
            // save the polyline returned by the map for later use
            polylines.add(mMap.addPolyline(progress[0]));
        }
    }

...

@Override
protected void onPostExecute(Boolean result) {

    if (pd != null) {
        pd.dismiss();
        pd = null;
    }

【讨论】:

  • 谢谢,但我的问题不是加载线条,而是线条在地图上之后的性能。瓷砖覆盖似乎是一种解决它的方法。
  • 我对地图的性能没有任何问题,在每条 50 段的折线上有 3000++ 个坐标。 600 条折线在性能上没有问题:一秒钟即可绘制,地图移动仍然流畅流畅。
  • 我认为这是折线的数量而不是坐标的数量。在我的应用程序中,我在任何给定时间都有 1000 多条折线。无论如何,瓷砖覆盖物就像一个魅力。感谢您的意见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
相关资源
最近更新 更多