【问题标题】:MapView in ListView hangs after resetting marker location or moving camera (Google Map Android API v2)ListView 中的 MapView 在重置标记位置或移动相机后挂起(Google Map Android API v2)
【发布时间】:2016-06-05 03:47:17
【问题描述】:

我在 ListView 中有一个 MapView(精简模式)。这是按照以下示例中的方法完成的: https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java

此 MapView 的 XML 代码如下所示:

<com.google.android.gms.maps.MapView android:id="@+id/mapLocation"
    android:layout_width="match_parent"
    android:layout_height="@dimen/google_map_height"
    map:liteMode="true"
    map:mapType="none"
    android:layout_below="@+id/textTitle"
    android:visibility="gone"
    android:padding="@dimen/image_padding"
    android:apiKey="AIzaSyBDOINR0EcGYu9RDUY1******"/>

第一次加载地图时,我能够放置一个标记并正确设置相机。一切看起来都很正常,ListView 的滚动看起来很流畅。当用户单击 MapView 时,它还能够生成 onMapClick() 事件。但是,稍后当我尝试使用以下代码移动标记或重置相机视图时,MapView 挂起:

// Update GUI
boolean hasLocation = (targetLatLng != null);
MapView mapView = (MapView) view.findViewById(R.id.mapLocation);
if (mapView != null) {
    if (hasLocation) {
        mapView.setVisibility(View.VISIBLE);
        if (listViewGoogleMap != null) {
            listViewGoogleMap.moveCamera(
                    CameraUpdateFactory.newLatLngZoom(targetLatLng, 13f));
//          if (markerListViewMap != null)
//              markerListViewMap.setPosition(targetLatLng);
//          else
//              markerListViewMap = listViewGoogleMap.addMarker(new MarkerOptions()
//                      .position(targetLatLng));
        } else {
            mapView.setVisibility(View.GONE);
        }
    }
}

请注意,我已经注释掉了 Marker.setPosition() 部分,该部分用于在地图上移动标记。如果我同时注释掉 moveCamera() 语句和 Marker.setPosition() 部分,则不再发生挂起。

发生挂起时,MapView 不再响应鼠标点击(不触发 onMapClick() 事件)。 ListView 的滚动变得明显迟缓。此外,调试日志中还会出现大量关于 CPU 和内存消耗的警告:

06-05 10:35:55.731 11672-11672/cards.myb.mybusinesscards D/CardEditorMapRow:      Longitude/latitude obtained from dialog : (23.0238082, 120.2276839)
06-05 10:35:55.731 11672-11672/cards.myb.mybusinesscards D/CardEditorMapRow: Address obtained from dialog:
06-05 10:35:56.557 11672-11683/cards.myb.mybusinesscards I/art: Background sticky concurrent mark sweep GC freed 626(33KB) AllocSpace objects, 5(13MB) LOS objects, 22% free, 46MB/59MB, paused 21.757ms total 32.972ms
06-05 10:35:57.653 11672-11678/cards.myb.mybusinesscards W/art: Suspending all threads took: 11.688ms
06-05 10:35:58.155 11672-11678/cards.myb.mybusinesscards W/art: Suspending all threads took: 13.849ms
06-05 10:35:58.410 11672-11683/cards.myb.mybusinesscards I/art: Background partial concurrent mark sweep GC freed 701(35KB) AllocSpace objects, 10(16MB) LOS objects, 26% free, 43MB/59MB, paused 5.653ms total 28.354ms
06-05 10:35:58.551 11672-11683/cards.myb.mybusinesscards I/art: Background sticky concurrent mark sweep GC freed 587(32KB) AllocSpace objects, 5(13MB) LOS objects, 22% free, 46MB/59MB, paused 10.637ms total 20.616ms
06-05 10:36:00.283 11672-11683/cards.myb.mybusinesscards I/art: Background partial concurrent mark sweep GC freed 791(40KB) AllocSpace objects, 11(19MB) LOS objects, 26% free, 43MB/59MB, paused 9.291ms total 34.966ms
06-05 10:36:01.802 11672-11683/cards.myb.mybusinesscards I/art: Background partial concurrent mark sweep GC freed 833(42KB) AllocSpace objects, 11(19MB) LOS objects, 26% free, 43MB/59MB, paused 5.594ms total 31.557ms
06-05 10:36:04.676 11672-11678/cards.myb.mybusinesscards W/art: Suspending all threads took: 18.995ms

一种解决方法是重新创建整个活动。 (再次隐藏和显示 MapView 无济于事)感谢任何 cmets!

2016 年 6 月 6 日编辑: 经过进一步调试后,我意识到这是由于某种与 MapView 组件相关的无限循环。在每次 MapView 的 ViewTreeObserver 调用 OnGlobalLayout() 时添加一条显示调试消息的语句后,我看到 数千 条消息(并且还在计数......),如下所示:

06-06 06:39:48.532 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2681
06-06 06:39:48.581 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2682
06-06 06:39:48.658 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2683
06-06 06:39:48.688 11208-11219/cards.myb.mybusinesscards I/art: Background 
sticky concurrent mark sweep GC freed 511(27KB) AllocSpace objects, 4(10MB)
LOS objects, 16% free, 53MB/64MB, paused 10.956ms total 23.201ms
06-06 06:40:04.141 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2684
06-06 06:40:04.183 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2685
06-06 06:40:04.212 11208-11208/cards.myb.mybusinesscards D/CardEditorMapRow:
onGlobalLayout() count=2686

【问题讨论】:

  • 您的垃圾收集器调用可能会挂起您的主线程。这是因为回收视图时正在释放 MapView 资源。检查那可能是地图标记还是地图视图本身。
  • 谢谢!你的观点很好。我沿着这条线做了一些进一步的检查。实际上,在 onGlobalLayout() 调用之间有很多 ListAdapter.getView() 调用和 onMovedToScrapHeap() 调用。不过,这个问题似乎很复杂,因为我的 ListView 中的每一行都有不同的布局。我需要对此进行更多调查..

标签: android google-maps listview android-mapview


【解决方案1】:

如应用清单中所述 - android:hardwareAccelerated

启用硬件加速渲染器后,Canvas、Paint、Xfermode、ColorFilter、Shader 和 Camera 中的大多数操作都会被加速。这会带来更流畅的动画、更流畅的滚动和整体上改进的响应能力,即使对于没有明确使用框架的 OpenGL 库的应用程序也是如此。

如果您的 API 级别 >= 11,您可以通过在 Android 清单文件中添加以下属性来启用 hardware acceleration

<application android:hardwareAccelerated="true"/>

这篇 SO 帖子 - Enable hardware acceleration in Android app, targeting Honeycomb AND prior versions 还可以帮助您在启用硬件加速之前在清单中添加所需的属性。

【讨论】:

  • 感谢您的及时评论。根据 Google 的文档,我相信 MapView 会自动使用 OpenGL。反正我试过了。不幸的是,结果似乎是一样的。
【解决方案2】:

抱歉,问题发布得很糟糕。事实证明,问题出在我的 ListView 中有多种不同类型的布局。

因此,每种布局类型都由不同的类处理。我的 ListAdapter 将 getView() 调用传递给每种布局类型的不同处理程序类。例如,当布局是由 MapView 组成的布局时,以下函数会处理:

public class MapRow {
    View view = null;

    public View getView(ViewGroup parent, Context context)
    {
        // Create view if it does not exist yet
        if(view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.map_row, parent, false);
            initializeMap();

            view.setTag("map");
        }
        return view;
    }
}

该策略适用于不包含图像的布局。但是当我在里面有一个 MapView 时,一旦地图在第一次创建后得到更新,就会在 MapView 的 invalidate() 函数请求全局布局和外部 ListView 的 getView() 调用之间循环。正是这种无限循环导致 GUI 变慢。

给大家的建议:在覆盖getView()函数的时候,按照this example一样重用“convertView”的约定。否则可能会发生坏事。

我自己的问题的解决方案是用一个简单的LinearLayout替换ListView,动态创建视图。如果里面的每一个item都不一样,用ListView真的没有什么好处,回收的view也不能重复使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 2013-08-27
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多