gpt4 book ai didi

Android MapView 叠加,在绘制时缓存位图

转载 作者:行者123 更新时间:2023-11-29 18:05:38 33 4
gpt4 key购买 nike

我有一个用于在我的 MapView 上绘制路径的叠加层,但我注意到它每秒被不必要地重绘大约十次。由于在 draw 方法中我绘制了路径的每一段,这很容易成为效率问题。

出于这个原因,我决定缓存叠加层的内容,并在必要时实际重绘它,即当路径更改、 map 中心移动或缩放级别更改时。

现在,draw 方法的参数之一是要绘制的 Canvas。我知道如何在上面绘制缓存的位图,问题是我不知道如何在位图上缓存 Canvas 的内容。
我无法实例化新 Canvas ,也无法调用 setBitmap,因为 HardwareCanvas 中的 Canvas ,如果该方法是,它会抛出 UnsupportedOperationException调用。

那么,回顾一下,我有一个 Canvas 和一个位图,我如何将 Canvas 的内容复制到位图?

编辑
为清楚起见,这是我的绘制方法,我没有手动调用它,但即使 map 根本没有移动,它仍然会被重复调用

public void draw(Canvas canvas, MapView map, boolean shadow) {
if (shadow) {
// this overlay doesn't need to draw shadows
return;
}
if (paths.isEmpty()) {
// nothing to draw
return;
}
center = map.getMapCenter();
zoomLevel = map.getZoomLevel();
map.getDrawingRect(bounds);
projection = map.getProjection();
maxLevel = map.getMaxZoomLevel();
for (MapPath mp : paths) {
// adjust path width to current zoom
adjustedWidth = mp.getWidth() * zoomLevel / maxLevel;
if (adjustedWidth < MIN_WIDTH_TO_DRAW) {
// path is too thin, avoid drawing it
continue;
}
paint.setStrokeWidth(adjustedWidth);
paint.setColor(mp.getColor());
state = PathState.FIRST_POINT;
path.reset();
for (PathPoint pp : mp.getPoints()) {
if (!pp.shoudAppearAtZoomLevel(zoomLevel)) {
// do not draw this point at this zoom level
continue;
}
// project a geopoint to a pixel
projection.toPixels(pp.getGeoPoint(), point);
inside = isInsideBounds(point, map);
switch (state) {
case FIRST_POINT:
// move to starting point
firstX = point.x;
firstY = point.y;
path.moveTo(firstX, firstY);
break;
case WAS_INSIDE:
// segment is completely or partially on map
path.lineTo(point.x, point.y);
break;
case WAS_OUTSIDE:
if (inside) {
// segment is partially on map
path.lineTo(point.x, point.y);
} else {
// segment is completely off map
path.moveTo(point.x, point.y);
}
break;
}
// update state
state = inside ? PathState.WAS_INSIDE : PathState.WAS_OUTSIDE;
}
// workaround to avoid canvas becoming too big when path is mostly off screen
path.moveTo(firstX, firstY);
// draw this path to canvas
canvas.drawPath(path, paint);
}
super.draw(canvas, map, shadow);
}

最佳答案

您无法将位图获取到 Mapviewcanvas 正在绘制的位置。

方法应该如下:

  • 首先,您创建自己的(空的和透明的)位图,其大小与 MapView Canvas
  • 然后为您的位图创建 Canvas (此 Canvas 是您用来绘制位图的绘图工具)并使用它绘制路径。
  • 最后,您将位图(路径已绘制)绘制到 MapView Canvas 上。

但是,您提到的性能/效率问题可能是由于现有解决方案的设计不正确造成的。在中等范围的设备中,我可以在大约 3 毫秒内绘制 10.000 个点的路径而不使用位图(并且有一些不使用它们的充分理由)。

在我对这篇文章的回答中,有一些关于如何处理它的提示:Overlay.draw() calls many times .另请检查同一篇文章中@shkschneider 的回答。

--编辑--

仅通过查看代码,我无法弄清楚为什么您会收到此警告...但正在使其变得比需要的复杂得多。

按以下方式组织代码:

绘制

draw() 方法仅检查是否有缩放更改(如果有则要求重建路径)以及 map 是否已移动(如果有偏移路径)并最终绘制路径。

@Override
public void draw(Canvas canvas, MapView mapview, boolean shadow) {
super.draw(canvas, mapview, shadow);
if(shadow) return;
if(mp.getPoints() == null || mp.getPoints().size() < 2) return;

Projection projection = mapview.getProjection();
int lonSpanNew = projection.fromPixels(0,mapview.getHeight()/2).getLongitudeE6() -
projection.fromPixels(mapview.getWidth(),mapview.getHeight()/2).getLongitudeE6();
if(lonSpanNew != pathInitialLonSpan)
pathBuild();
else{ //check if path need to be offset
projection.toPixels(mp.getPoints().get(0), p1);
if(p1.x != pathInitialPoint.x || p1.y != pathInitialPoint.y){
path.offset(p1.x - pathInitialPoint.x, p1.y - pathInitialPoint.y);
pathInitialPoint.x = p1.x;
pathInitialPoint.y = p1.y;
}

}
canvas.drawPath(path, paint);
}

路径构建

每次缩放更改时都必须构建路径。缩放变化检测是使用 pathInitialLonSpan 完成的,因为 getZoomLevel() 与 map 缩放动画不同步。

private void pathBuild(){
path.rewind();
if(mp.getPoints() == null || mp.getPoints().size() < 2) return;

Projection projection = mapView.getProjection();
pathInitialLonSpan = projection.fromPixels(0,mapView.getHeight()/2).getLongitudeE6() -
projection.fromPixels(mapView.getWidth(),mapView.getHeight()/2).getLongitudeE6();

projection.toPixels(mp.getPoints().get(0), pathInitialPoint);
path.moveTo(pathInitialPoint.x,pathInitialPoint.y);

for(int i=1; i<mp.getPoints().size(); i++){
projection.toPixels(mp.getPoints().get(i), p1);
int distance2 = (pPrev.x - p1.x) * (pPrev.x - p1.x) + (pPrev.y - p1.y) * (pPrev.y - p1.y);
if(distance2 > 9){
path.lineTo(p1.x,p1.y);
pPrev.set(p1.x, p1.y);
}
}

某些对象(即 p1、pPrev 等)是在类级别定义的,以避免每次方法运行时都创建新对象。

注意:我已经更改了变量名称以适合您正在使用的名称。我希望我没有犯任何错误,但你应该能够弄清楚这一点。

问候。

关于Android MapView 叠加,在绘制时缓存位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13556435/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com