安卓谷歌地图中的高效地图叠加

21

我想做以下的事情,但是在这些问题上卡了几天了:

  1. 我正在尝试绘制折线(我有编码后的折线,但已经成功解码了),当我移动地图时需要实现折线跟着移动
    我找到的唯一解决方案是将Geopoints转换为屏幕坐标...这种方法无法随着地图的移动而移动。

  2. 我使用 HelloItemizedOverlay 添加了约 150 个标记,但运行非常缓慢
    有什么想法吗?我正在考虑使用线程(handler)。

  3. 我正在寻找一种类似于定时器函数以周期性地执行给定的函数,比如每 1 分钟执行一次。

  4. 我还在寻找清除 Google 地图上所有标记/线等内容的方法。


1
问题1已解决...我在浏览stackoverflow.com时找到了答案... :) 解决方案发布在这里https://dev59.com/dnI95IYBdhLWcg3wvgl9 - Ahsan
1
q4...问题已解决,我在stackoverflow.com上找到了答案...解决方法是:使用以下代码if(!mapOverlays.isEmpty()) { mapOverlays.clear(); mapView.invalidate(); } - Ahsan
3
q2问题已解决,答案来自stackoverflow.com ...创建标记(createMarkers)函数: 对于bigList中的每个元素(elem),创建一个GeoPoint对象和一个OverlayItem对象,并将OverlayItem对象添加到itemizedOverlay中。 其中,GeoPoint对象使用元素的纬度(lat)和经度(lon)乘以1000000转换得到。 最后,调用itemizedOverlay的populateNow()方法来填充Overlay列表,并将其添加到地图(mapOverlays)图层中。MyOverlay类中的addOverlay方法:将传入的OverlayItem对象添加到m_overlays列表中。 populateNow方法:调用父类Overlay的populate()方法来更新Overlay状态。 - Ahsan
1
q 3已解决.... 在stackoverflow.comhttps://dev59.com/WnI-5IYBdhLWcg3wZ3YR - Ahsan
1
q3 --更好的方法 :)http://life.csu.edu.au/java-tut/essential/threads/timer.html - Ahsan
显示剩余4条评论
5个回答

11

以下是给出的答案:

1)这是我使用的解决方案:

/** Called when the activity is first created. */
private List<Overlay> mapOverlays;

private Projection projection;  

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    linearLayout = (LinearLayout) findViewById(R.id.zoomview);
    mapView = (MapView) findViewById(R.id.mapview);
    mapView.setBuiltInZoomControls(true);

    mapOverlays = mapView.getOverlays();        
    projection = mapView.getProjection();
    mapOverlays.add(new MyOverlay());        

}

@Override
protected boolean isRouteDisplayed() {
    return false;
}

class MyOverlay extends Overlay{

    public MyOverlay(){

    }   

    public void draw(Canvas canvas, MapView mapv, boolean shadow){
        super.draw(canvas, mapv, shadow);

    Paint   mPaint = new Paint();
        mPaint.setDither(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(2);

        GeoPoint gP1 = new GeoPoint(19240000,-99120000);
        GeoPoint gP2 = new GeoPoint(37423157, -122085008);

        Point p1 = new Point();
        Point p2 = new Point();

    Path    path = new Path();

    Projection  projection.toPixels(gP1, p1);
        projection.toPixels(gP2, p2);

        path.moveTo(p2.x, p2.y);
        path.lineTo(p1.x,p1.y);

        canvas.drawPath(path, mPaint);
    }

致谢:如何在Google地图上绘制线条/路径

2)以下是我实际使用的方法:

createMarkers()
{ 
    for(elem:bigList)
    { 
        GeoPoint geoPoint = new GeoPoint((int)(elem.getLat()*1000000), (int) (elem.getLon()*1000000)); 
        OverlayItem overlayItem = new OverlayItem(geoPoint, elem.getName(), elem.getData()); 
        itemizedOverlay.addOverlay(overlayItem); 
    } 

    itemizedOverlay.populateNow(); 
    mapOverlays.add(itemizedOverlay); //outside of for loop 
} 

并且在MyOverlay中:

public void addOverlay(OverlayItem overlay) 
{ 
    m_overlays.add(overlay); 
} 

public void populateNow()
{
    populate(); 
}

参考:stackoverflow.com 不知名链接

3) 最好的方法是使用计时器类。该链接详细描述了计时器类及其使用方法:

http://life.csu.edu.au/java-tut/essential/threads/timer.html

4) 我使用了以下代码:

if(!mapOverlays.isEmpty()) 
{ 
    mapOverlays.clear(); 
    mapView.invalidate(); 
} 

希望这些答案能够帮助至少一个人。谢谢。


1
你应该在单独的回答中提供你的解决方案,而不是在评论中。这对每个人都更好,也使你能够为代码使用格式。 - Catalin Morosan
1
你真是太棒了。我有一个任务需要在地图上标记200/300个点,但我遇到了平滑度不足的问题。所以在我的研究和开发过程中,我偶然发现了这篇文章,而你就是那位能够解决我的问题的人。非常感谢你。在标记多个点的解决方案中,这是第二步。 - Paresh Mayani
1
非常感谢你们,朋友们。我在过去的两天里一直苦恼,但你们的解决方案真是太棒了。 - QuokMoon

2
我遇到了同样的问题。我们同时在开发 iPhone 应用和 Android 应用。我有 2500+ 个地图覆盖层。在 iPhone 上没有问题;但在 Android 上,添加所有覆盖层后调用 populate() 方法会导致性能严重下降。 (当然,我的第一次尝试是每次添加覆盖层后都调用 populate() 方法;这是由于 Google 的教程所导致的典型错误。现在我只在所有 2500+ 个覆盖层都添加完毕后调用一次 populate() 方法。)
因此,在 htc hero 设备上,单个 populate() 方法调用需要超过 40 秒才能完成。我不得不加入一个繁忙指示器;无法使用进度条,因为我们无法获取有关 populate() 进度的任何信息。
我尝试了另一种解决方案:不使用 ItemizedOverlay,而是手动添加覆盖层,子类化 Overlay。结果:确实更快地将所有覆盖层添加到地图上;但由于对每个覆盖层都不断调用 draw() 方法,使得地图无法使用。在我的 draw() 方法中,我尽可能进行了优化;我不会每次都创建位图。我的 draw() 方法看起来像这样:
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)  {
// our marker bitmap already includes shadow.
// centerPoint is the geopoint where we need to put the marker.
 if (!shadow) {
  Point point = new Point();  
  mapView.getProjection().toPixels(centerPoint, point);
  canvas.drawBitmap(markerBitmap, point.x, point.y, null);
 }

}

这里的markerBitmap是预先计算好的。我不知道还能优化什么。如果我们没有使用ItemizedOverlay,是否需要某种populate()调用?我找不到任何好的答案。

现在,我会在后台线程中缓存ItemizedOverlay一旦它被创建。这样,至少用户不必每次等待。


在Android上添加2500个标记实际上是不可能的。该项目的解决方案是首先找出当前地图部分可见的标记。(这必须在每次平移/缩放后重新计算。)然后我们检查是否有<100个标记,否则不需要显示所有标记。100个标记可以在几秒钟内添加到地图上。当然,所有这些都在后台线程上完成,因此用户在等待populate()完成时看到旋转的圆圈。在iPhone上,类似的代码是瞬间完成的(2500个标记也有点慢)。 - winitzki

0
对于#2,我认为你没有解决任何问题。你难以阅读的代码展示了如何在叠加层上放置标记,然后将该叠加层添加到地图上。这正是我所做的。我有一张地图,周围有大约300家酒店,Android在我的Nexus One上创建标记需要大约5秒钟。整个过程在线程内运行,我想我必须做某种进度条来让用户知道正在发生什么。
我正在开发一个已经存在于iPhone上的应用程序,似乎iPhone没有任何问题几乎瞬间绘制这300多个标记。我将难以向我的老板解释进度条的存在。
如果有人有优化这个过程的想法...我将不胜感激。
这是我的代码:
    ...
        for (int m = 0; m < ArrList.size(); m++) {
            tName = ArrList.get(m).get("name").toString();
            tId = ArrList.get(m).get("id").toString();
            tLat = ArrList.get(m).get("lat").toString();;
            tLng = ArrList.get(m).get("lng").toString();;
            try {
                lat = Double.parseDouble(tLat);
                lng = Double.parseDouble(tLng);
                p1 = new GeoPoint(
                        (int) (lat * 1E6), 
                        (int) (lng * 1E6));
                OverlayItem overlayitem = new OverlayItem(p1, tName, tId);
                itemizedoverlay.addOverlay(overlayitem);
            } catch (NumberFormatException e) {
                Log.d(TAG, "NumberFormatException" + e);    
            }
        } 

我知道如果避免这个字符串>双精度转换,我可以节省一些时间,但我觉得这不会给我带来显著的节省...或者会吗?


-2
针对您的第四个问题,只需使用mapOverlays.clear();方法即可清除所有先前的标记。
if(!mapOverlays.isEmpty()) { 
    mapOverlays.clear();
    mapView.invalidate();
}

-3
可以将多个可绘制对象添加到单个叠加层中,然后将其添加到地图上。因此,除非对象是不同类型的,否则不需要为 x 个对象绘制 x 个叠加层。代码片段...
在这里,CustomPinPoint 是我的类,它扩展了 ItemizedOverlay<OverlayItem>
CustomPinPoint customPinPoint = new CustomPinPoint(drawable, Main.this);

OverlayItem tempOverLayItem = new OverlayItem(
    touchedPoint, "PinPoint", "PintPoint 2"); //Point One
customPinPoint.insertPinPoint(tempOverLayItem);
tempOverLayItem = new OverlayItem(new GeoPoint(
        (int)(-27.34498 * 1E6), (int)(153.00724 * 1E6)), "PinPoint",
    "PintPoint 2"); //Point Two
customPinPoint.insertPinPoint(tempOverLayItem);
overlayList.add(customPinPoint); //Overlay added only once

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接