如何在使用叠加层时缓存android.graphics.path或者Bitmap?

我使用Overlay来绘制Google地图上的区域,绘制出我从任何来源获得的成千上万个GeoPoint的形状。 这工作,看起来像这样:

    @Override
    public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)  {
        super.draw(canvas, mapView, false);

        Projection projection = mapView.getProjection();

        List<Zone> zones = ApplicationContext.getZones();

        path.rewind();

        for (Zone zone : zones) {
            paint.setDither(true);
            paint.setStyle(Style.FILL);
            paint.setAlpha(40);

            MultiPolygon multiPolygon = zone.getMultiPolygon();
            List<Polygon> polygons = multiPolygon.getPolygons();

            for (Polygon polygon : polygons) {
                for (List<Coordinate> coordinates : polygon.getCoordinates())  {
                    for (int i = 0; i < coordinates.size(); i++)  {
                        Point p = new Point();

                        projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);

                        if (i == 0)  {
                            path.moveTo(p.x, p.y);
                        }
                        else  {
                            path.lineTo(p.x, p.y);
                        }
                    }
                }
            }
        }

        canvas.drawPath(path, paint);
    }

问题是这非常耗费资源。 每次在MapView上滚动或移动地图时,都必须重复计算路径,因为像素坐标已更改。 绘制的区域可能会变得非常大,以至于MapView上的滚动速度太慢,以至于无法使用。

我的想法是

  • 以某种方式缓存路径生成的“形状”,并在MapView上的缩放级别发生变化时重新绘制它。
  • 以某种方式在“即时”位图上绘制该绘图,将其用作Overlay(可能为ItemizedOverlay),侦听MapView滚动并以滚动的距离移动位图。
  • 我不确定是否有更好的方法。

    任何想法如何我可以解决这个问题? (我正在使用Google Maps API 1,无法更改)。


    在试图找出如何匹配地图的移动之前,对当前的代码进行一些优化可能会产生显着的节省。 特别是,内循环中的这两行执行次数最多,但执行起来相当昂贵(两次内存分配,浮点乘法和四次方法调用)。

    Point p = new Point();    
    projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);
    

    首先,你只需要一个Point对象,所以不要在你的循环中分配它。 把它移动到你的path.rewind();下面path.rewind();

    第二,如果你预先计算的坐标GeoPoints而不是每次都计算它们,你将节省大量的处理您的draw程序。 您也可以摆脱那if有一点点工作报告。 假设您将coordinate列表预先转换为GeoPoint列表,并通过polygon.getGeoCoordinates()使其可用,则最终可能会看到内部循环 -

    for (List<GeoPoint> geoCoordinates : polygon.getGeoCoordinates())  {
        projection.toPixels(geoCoordinates.get(0),p);
        path.moveTo(p.x, p.y);  // move to first spot
        final List<GeoPoint> lineToList = geoCoordinates.sublist(1,geoCoordinates.size());  // A list of all the other points
        for(GeoPoint gp : lineToList) {
            projection.toPixels(gp, p);
            path.lineTo(p.x, p.y);
         }
    }
    

    那会比以前做的更快。


    经过最后几天的修改之后,我发现了一个可能的解决方案(我认为没有更好的解决方案)不要一遍又一遍地绘制路径,但将其移动到当前位置。

    困难的部分是弄清楚如何缓存绘制的形状,而不是一遍又一遍地计算它。 这可以通过使用矩阵来完成。 有了这个矩阵(我想这是一种“模板”),你可以操纵路径内的点坐标。 第一次(当某人开始移动地图时),我照常绘制该地区。 当它试图第二次或更多次计算它时,我不重绘形状,但是通过计算从当前点到最后一点的“增量”来操纵路径。 我知道当前的观点是什么,因为我始终将原始GeoPoint(始终保持不变)映射到当前投影产生的点。 “三角洲”需要设置为矩阵。 之后,我通过使用这个新的矩阵来改变路径。 结果非常快。 地图的滚动速度与不使用覆盖图一样快。

    这看起来像这样(这不是生产代码,它还不能处理缩放,但它显示了我用作优化基础的原则):

    public class DistrictOverlay extends Overlay {
    
    //  private final static String TAG = DistrictOverlay.class.getSimpleName();
        private Paint paint = new Paint();
        private Path path = new Path();
        private boolean alreadyDrawn = false;
        private GeoPoint origGeoPoint;
        Point p = new Point();
        Point lastPoint = new Point();
    
        @Override
        public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
            super.draw(canvas, mapView, false);
    
            Projection projection = mapView.getProjection();
    
            List<Zone> zones = ApplicationContext.getZones();
    
            if (!alreadyDrawn) {
                path.rewind();
    
                for (Zone zone : zones) {
                    if (!zone.getZoneId().equals(MenuContext.getChosenZoneId())) {
                        continue;
                    }
    
                    String dateString = zone.getEffectiveFrom().trim().replace("CEST", "").replace("GMT", "").replace("CET", "").replace("MESZ", "");
                    if (DateUtil.isBeforeCurrentDate(dateString)) {
                        paint.setColor(Color.RED);
                    } else {
                        paint.setColor(Color.GREEN);
                    }
    
                    paint.setDither(true);
                    paint.setStyle(Style.FILL);
                    paint.setAlpha(40);
    
                    MultiPolygon multiPolygon = zone.getMultiPolygon();
                    List<Polygon> polygons = multiPolygon.getPolygons();
    
                    for (Polygon polygon : polygons) {
                        for (List<GeoPoint> geoPoints : polygon.getGeoPoints()) {
                            projection.toPixels(geoPoints.get(0), p);
                            path.moveTo(p.x, p.y);
    
                            origGeoPoint = new GeoPoint(geoPoints.get(0).getLatitudeE6(), geoPoints.get(0).getLongitudeE6());
                            lastPoint = new Point(p.x, p.y);
    
                            final List<GeoPoint> pathAsList = geoPoints.subList(1, geoPoints.size());
    
                            for (GeoPoint geoPoint : pathAsList) {
                                projection.toPixels(geoPoint, p);
                                path.lineTo(p.x, p.y);
                            }
                        }
                    }
                }           
            }
            else  {
                projection.toPixels(origGeoPoint, p);       
                Matrix translateMatrix = new Matrix();
                translateMatrix.setTranslate(p.x - lastPoint.x, p.y - lastPoint.y);
                path.transform(translateMatrix);
    
                lastPoint = new Point(p.x, p.y);
            }
    
            canvas.drawPath(path, paint);
    
            if (!path.isEmpty()) {
                alreadyDrawn = true;
            }
        }
    
        @Override
        public boolean onTap(GeoPoint p, MapView mapView) {
            return true;
        }
    }
    
    链接地址: http://www.djcxy.com/p/11757.html

    上一篇: How to cache android.graphics.path or Bitmap when using Overlays?

    下一篇: Android app loading screen background image takes too long to load