android - Android Google Maps API 中数以千计的多边形给主线程带来了负担

标签 android api maps polygons

我正在开发一个应用程序,用于从文本文件中的给定 GPS 位置绘制移动路径。 到目前为止,我已经成功加载数据并绘制路径。 我的解决方案是,路径必须绘制成一个矩形,因为它包含数据(例如颜色和宽度)并且可点击。一条线不能做到这一点。此外,转弯时这些矩形之间也有一个三角形间隙,所以我用三角形填充它。而且路径必须是双倍的,因为我有另一个数据要显示在第二层上。这意味着,要为更长的路径绘制大量多边形。

我已经在 15 公里的旅程中尝试过这个,它需要 1000 行 gps 数据。 当我解析该文件时,它为两个图层总共绘制了多达 5000 个多边形。

我的问题是,当它绘制多达 1000 个多边形的形状时,应用程序变得迟缓,没有响应。如果我让线程休眠 1 秒,似乎没问题。但速度更快,它变得没有响应。

我一直在网上阅读这个解决方案并且可以找到它。 仅供引用,我已经创建了另一个线程来处理文本文件。 我还通过让应用程序在不绘制多边形的情况下执行该过程来缩小问题范围,并且过程很顺利。 我读到没有其他方法可以在主线程之外处理多边形。

更新: 我正在使用 Asynctask 背景从文本文件中读取一行,将其解析为包含纬度、经度、Value1、Value2 的数组。 然后在那里进行大量计算。 完成每一行后,我将对象发送到 onProgressUpdate 以使用标记、多段线和形状更新 UI 线程。

这是我的异步任务

private class DrawPathAsync extends AsyncTask<File, Object, Void>
{

    FileInputStream is;
    BufferedReader reader;



    @Override
    protected Void doInBackground(File... params) {
        File sFile = params[0];
        Integer count;
        String line = "";
        double radius = 8; //8 meter
        double distance;

        double Heading_y;
        int kaler, gkaler;
        double apprate, gi;

        if (sFile.exists()) {
            try {
                is = new FileInputStream(sFile);
                reader = new BufferedReader(new InputStreamReader(is));
                reader.readLine(); // this will read the first line


                while ((line = reader.readLine()) != null) {

                    String[] valuesArray = line.split("\\s*,\\s*");
                    Float bearing = (float) 0;

                    Double lat = Double.parseDouble(valuesArray[1]);
                    Double lng = Double.parseDouble(valuesArray[2]);

                    LatLng latlng = new LatLng(lat, lng);
                    LatLng center = latlng;
                    apprate = Double.parseDouble(valuesArray[3]); 

                    if (apprate >=0 && apprate < 80) {
                        kaler = appcolor1; 
                    } else if (apprate >=80 && apprate < 100) { 
                        kaler = appcolor2;
                    } else if (apprate >=100 && apprate < 120) {  
                        kaler = appcolor3;
                    } else if (apprate >=120 && apprate < 140) {  
                        kaler = appcolor4;
                    } else if (apprate >=140 && apprate < 160) {  
                        kaler = appcolor5;
                    } else if (apprate >=160 && apprate <= 200) {  
                        kaler = appcolor6;
                    } else {
                        kaler = appcolor7; 
                    }


                    if (points.size()== 2) {
                        points.remove(0);
                        points.add(latlng);
                    } else {
                        points.add(latlng);
                    }


                    //recheck
                    if (points.size() == 2) {

                        distance = SphericalUtil.computeDistanceBetween(center, points.get(0));

                        LatLng pt1 = points.get(0);
                        LatLng pt2 = latlng;

                        bearing = (float) SphericalUtil.computeHeading(pt1, pt2);
                        if (bearing < 0) {
                            bearing = bearing + 360;
                        }

                        LatLng x = SphericalUtil.computeOffset(center, radius, bearing - 90);
                        LatLng y = SphericalUtil.computeOffset(center, radius, bearing + 90);


                        LatLng a = SphericalUtil.computeOffset(x, distance, bearing + 180);
                        LatLng b = SphericalUtil.computeOffset(y, distance, bearing + 180);


                        MarkerPoint mp = new MarkerPoint();
                        mp.latlng = latlng;
                        mp.bearing = bearing;

                        Rect rc = new Rect();
                        rc.a = a;
                        rc.b = b;
                        rc.x = x;
                        rc.y = y;
                        rc.kaler = kaler;
                        rc.pt2 = pt2;

                        publishProgress(mp, rc);
                    }

                    Thread.sleep(50);

                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Object... values) {

        MarkerPoint mp = (MarkerPoint) values[0];
        Rect rc = (Rect) values[1];



        LatLng latlng = mp.latlng;

        BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.mipmap.pointer);
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latlng);
        markerOptions.icon(icon);
        markerOptions.rotation(mp.bearing);

        mMap.moveCamera(CameraUpdateFactory.newLatLng(latlng));
        marker1.remove();
        marker1 = mMap.addMarker(markerOptions);

        if (points.size() > 1) {
            path = mMap.addPolyline(new PolylineOptions().add(points.get(0)).add(points.get(1)).color(Color.BLUE).width(5));
            lines.add(path);
        }

        PolygonOptions options = new PolygonOptions()
                .fillColor(rc.kaler)
                .strokeWidth(0)
                .strokeColor(Color.TRANSPARENT);
        options.add(rc.x);
        options.add(rc.y);
        options.add(rc.b);
        options.add(rc.a);

        rect = mMap.addPolygon(options);
        rects.add(rect);

        if (tripoints.size() == 3) {
            tripoints.add(rc.a);
            tripoints.add(rc.b);
        } else {



            tripoints.add(rc.pt2);
            tripoints.add(rc.x);
            tripoints.add(rc.y);
        }

        //check
        //round 2, if triponts = 5 create triangle
        if (tripoints.size() == 5) {
            PolygonOptions options2 = new PolygonOptions()
                    .fillColor(rc.kaler)
                    .strokeWidth(0)
                    .strokeColor(Color.TRANSPARENT);

            options2.add(tripoints.get(0));
            options2.add(tripoints.get(2));
            options2.add(tripoints.get(4));


            t1 = mMap.addPolygon(options2);
            tris.add(t1);


            PolygonOptions options3 = new PolygonOptions()
                    .fillColor(rc.kaler)
                    .strokeWidth(0)
                    .strokeColor(Color.TRANSPARENT);

            options3.add(tripoints.get(0));
            options3.add(tripoints.get(1));
            options3.add(tripoints.get(3));



            t2 = mMap.addPolygon(options3);
            tris.add(t2);



            tripoints.clear();
            tripoints.add(rc.pt2);
            tripoints.add(rc.x);
            tripoints.add(rc.y);
        }


    }

    @Override
    protected void onPostExecute(Void result) {

    }
}

希望有人可以分享一些技巧和解决方案。

最佳答案

我遇到同样的问题已有一段时间了,经过广泛的研究后,我将问题隔离到了 Google Maps SDK 本身。在我的案例中有效的解决方案是使用 GroundOverlay并在正确的地理坐标处绘制自定义点/线/多边形。我发现这个库基本上是这样做的:

https://github.com/antoniocarlon/richmaps

通过一些调整,我能够创建一个渲染线程,它将绘图/过滤部分从主 UI 线程中分离出来,并且只在完成时更新 GroundOverlay。此外,我添加了一个简单但快速的算法来搜索当前可见的形状。通过这种方法,您可以获得一些好处:

  • 仅绘制当前视口(viewport)内的对象(Google Maps SDK 会这样做,但不会绘制彼此太近的形状,例如 600+)
  • 绘图是在一个线程中完成的,因此应用启动得到了显着改善
  • 您可以向 map 形状添加更多自定义选项,如 绘图是用 Canvas 完成的
  • 在我的案例中,600 多个镫骨的 map 渲染时间减少到大约 200 毫秒。

关于android - Android Google Maps API 中数以千计的多边形给主线程带来了负担,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46392527/

相关文章:

android - 如果列值减少,柱形图不会更新

api - 访问共享日历(例如通过 Office 365 REST API 访问 session 室)

java - 如何用Java创建平铺 map ?

android - 如何动态更新小部件(不等待 30 分钟调用 onUpdate)?

android - 带有图像的 ListView 中的性能不佳

java - 数据库不存储查询

javascript - 通过单击按钮简单地从 soundcloud 播放声音

api - 是否有必要为移动应用程序构建单独的 API 端点以访问 Rails Web 应用程序?

java - 我是否需要传单 map 源代码才能在 HTML 中使用?

css - 如何删除谷歌地图标题?