Android Google Map在添加400个标记时addMarker()非常缓慢

18

感谢您抽出时间阅读此内容。

大约一个月前(08/29/14),我在 Google Play 商店发布了一个应用程序,使用相同数量的标记,这并不是问题。然而,本周我注意到,当我打开我的应用程序时,在我的 Galaxy S5 上加载 400 个标记到地图上需要大约 10-20 秒钟,并且在默认地图标记图标的中心有一个小圆圈。在此之前,地图加载少于一秒钟。我没有更新或更改我的应用程序。我猜测 Google 更新了 Google 地图 API,而这种变化使得加载标记变得更慢了?有其他人遇到过类似情况吗?有其他人对此有信息吗?

我的应用程序可以免费在 Play 商店上下载。如果您想查看它加载缓慢的情况,可以搜索“NYS Canal Guide”。

这种方法在地图片段的 onCreateView() 中调用,此时地图已经初始化:

    private void addExistingMarkersToMap(){
    log("Adding existing markers to the map. poiAdapter size = " + poiAdapter.getCount());
    Marker marker;
    MarkerOptions markerOptions;

    for(MapMarker mapMarker : poiAdapter){
        if(markersNotFilteredOut(mapMarker)){
            markerOptions = mapMarker.getMarkerOptions();

            if(markerOptions != null && mapMarker != null){
                marker = mMap.addMarker(markerOptions);
                mapMarker.setMarker(marker);
            }
        }
    }
}

这是MapMarker类上的getMarkerOptions()方法:

public MarkerOptions getMarkerOptions() {
    return new MarkerOptions()
    .title(name)
    .position(new LatLng(lat, lng))
    .snippet(bodyOfWater + ", mile " + mile)
    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
}

完整的源代码在这里:github.com/olearyj234/NYS-Canal-Guide

编辑:

** 具体而言,唯一缓慢的部分是在初始化地图时加载标记(因此也是从一个导航选项卡切换回地图选项卡时)。当移动地图或执行其他操作时,它不会缓慢。

这里有一些日志:

当屏幕冻结几秒钟(5-15)因为正在加载标记时,这个日志会非常快速地产生。位图ID将继续递增一,当标记正在加载时,它会产生大约400个这样的日志。这表明它必须是与在屏幕上加载标记位图相关的问题。我正在使用默认的标记位图。

   10-01 15:45:07.222: D/skia(32108): GFXPNG PNG bitmap created width:16 height:32 bitmap id is 414

当应用程序完成将所有标记加载到地图上时,将生成此日志。

10-01 15:51:09.402: I/Choreographer(8353): Skipped 1130 frames!  The application may be doing too much work on its main thread.

当应用程序完成将所有标记加载到地图上时,此日志将出现14次。

10-01 15:59:13.882: I/dalvikvm-heap(8353): Grow heap (frag case) to 40.668MB for 4194320-byte allocation

编辑2:

我刚刚检查了一下某些代码行所需的时间。我使用了System.currentTimeMillis();以获取时间。在方法addExistingMarkersToMap()中,这是需要长时间运行的行:marker = mMap.addMarker(markerOptions); 当添加所有400个标记时,每个标记平均需要54毫秒。最短时间为34毫秒,最长时间为114毫秒。

如果您认为还有其他信息需要提供,请在评论中告诉我。 谢谢!


我也重现了这个错误,即使您缓存图标BitmapDescriptor,添加标记的速度仍然很慢。 - eliocs
@eliocs 这个问题最近一个月内也发生在你身上了吗?我正在积极寻找解决方案,但我无法解决这个问题。另外,您如何选择缓存BitmapDescriptor图标? - James
他们可能会重新设计API,因为可穿戴设备API即将推出,假设可穿戴设备将会使用大量GPS(因此可能是地图)功能。这只是一个猜测,但如果你没有改变任何东西,那就是我的意见。 - zgc7009
@zgc7009 我同意,我认为自从我没有更改任何内容以来,他们已经更改了他们的API。无论他们更改了什么,我认为它与将位图添加到地图有关。你能看一下我刚刚添加到原始帖子中的日志吗?谢谢! - James
1
有一个中间解决方案,只添加在地图上可见的标记。建议参考此处:https://dev59.com/WmYr5IYBdhLWcg3wYpUg - eliocs
@olearyj234 我也遇到了大约390个标记的完全相同的行为。没有发布任何更改,它就开始出现了。我今天才注意到这一点。你找到了任何解决方案或变通方法吗? - myanimal
2个回答

13
这似乎是在Google Maps API v2中引入的新问题(看起来像Play Services 6更新之一),有关更多信息,请参见#7174(并请点赞)。
根据问题提供的信息,问题似乎特定于使用默认标记和色调,例如:
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)

有一些解决方法。最简单的方法是不提供色调(如果您可以接受所有标记都是红色):

BitmapDescriptorFactory.defaultMarker()

或使用自定义绘制对象:

BitmapDescriptorFactory.fromResource(R.drawable.map_marker)

当使用默认标记和色调时,我发现速度减慢了大约2000倍。目前我选择使用自定义可绘制对象作为解决方案。


1
7174是我的bug。我发现谷歌做了另一个改变 - 以前你只能使用工厂中静态定义的颜色(HUE_RED)。如果您提供了未定义的浮点数,它将简单地使用最近定义的颜色。现在,您可以使用任何浮点数来获得动态阴影。我敢打赌这就是他们引入问题的地方。 - Nemi
@myanimal 感谢您的积极回应。我已经标记了7174个错误。有人知道我可以使用的免费标记图标集吗?我想找到一个好的图标集并使用fromResource方法。如果我找到了一个好的图标集,我会在这里发布链接。 - James
我也收藏了它。我的问题出现在大约500个默认标记和自定义色调上。删除自定义色调后,它就像魔术般地工作了。因此确认色调是问题所在! - PLM57
在我改用自定义标记的时候(我是在Photoshop中创建它们的),使用fromResource方法后,它也能正常工作了。希望他们能尽快修复这个bug,以便其他使用不同色调的默认标记的人也能正常使用。 - James
5
如果有人遇到这些问题并想要使用我用Photoshop创建的图标,可以随意使用。你可以在https://github.com/olearyj234/NYS-Canal-Guide/tree/master/res的“drawable”文件夹中找到它们。每个图标的文件名都以“mmi”开头。 然后,您可以使用BitmapDescriptorFactory.fromResource(R.drawable.map_marker)来避免这个错误。 - James
1
这个 bug 已经在 Google Play 服务中得到修复,根据那个链接。我可以确认现在它对我有效。 - Nemi

4
据我的理解,每次绘制标记时,它会将绘图操作发送到后台的线程池,同时返回标记。如果请求过于频繁,则很容易使CPU不堪重负。
请使用主线程的处理程序并以递增间隔延迟发布,以分散操作,如下面的代码所示。
Handler handler = new Handler(Looper.getMainLooper());
int x = 0;
long DELAY = 10;
for(MapMarker mapMarker : poiAdapter){
    if(markersNotFilteredOut(mapMarker)){
        markerOptions = mapMarker.getMarkerOptions();

        if(markerOptions != null && mapMarker != null){
           handler.postDelayed(
                   new Runnable() {
                      @Override
                      public void run() {
                          marker = mMap.addMarker(markerOptions);
                          mapMarker.setMarker(marker);
                      }
                   }, (DELAY * (long)x++));
        }
    }
}

我修改了代码,使其与您上面的代码相似,但仍然出现了相同的延迟。我编辑了原始帖子以包含一些日志。也许这可以帮助您帮助我?谢谢您的回复! - James

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