Android Google Maps API 中的数千个多边形加重了主线程的负担

luc*_*mma 5 api maps android polygons

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

我在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) {

    }
}
Run Code Online (Sandbox Code Playgroud)

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

Geo*_*rgi 3

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

https://github.com/antoniocarlon/richmaps

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

  • 仅绘制当前视口内的对象(Google Maps SDK 会执行此操作,但不适用于彼此太接近的形状,例如在 600+ 的情况下)
  • 绘图是在线程中完成的,因此应用程序的启动得到了极大的改善
  • 当使用 Canvas 完成绘图时,您可以向地图形状添加更多自定义选项
  • 在我的例子中,对于 600 多个镫骨,地图渲染时间减少到大约 200 毫秒。