重置标记位置或移动相机后,ListView 中的 MapView 挂起 (Google Map Android API v2)
MapView in ListView hangs after resetting marker location or moving camera (Google Map Android API v2)
我在 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
解决方法是重新创建整个 activity。 (再次隐藏和显示 MapView 没有帮助)感谢任何评论!
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
如应用清单中所述 - android:hardwareAccelerated
when the hardware-accelerated renderer is enabled, most operations in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated. This results in smoother animations, smoother scrolling, and improved responsiveness overall, even for applications that do not explicitly make use the framework's OpenGL libraries.
如果您的 API 级别 >= 11,您可以通过在 Android 清单文件中添加以下属性来启用 hardware acceleration:
<application android:hardwareAccelerated="true"/>
此 SO post - Enable hardware acceleration in Android app, targeting Honeycomb AND prior versions 还可以帮助您在启用硬件加速之前在清单中添加所需的属性。
抱歉,问题发布不当。事实证明,问题是由于我的 ListView 中有多种不同类型的布局。
因此,每种布局类型都由不同的 class 处理。我的 ListAdapter 将 getView() 调用传递给每种布局类型的不同处理程序 classes。例如,当布局是由 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,并创建动态视图。如果里面的每一项都不一样,使用ListView真的没有任何优势,而且回收视图无法重复使用。
我在 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
解决方法是重新创建整个 activity。 (再次隐藏和显示 MapView 没有帮助)感谢任何评论!
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
如应用清单中所述 - android:hardwareAccelerated
when the hardware-accelerated renderer is enabled, most operations in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated. This results in smoother animations, smoother scrolling, and improved responsiveness overall, even for applications that do not explicitly make use the framework's OpenGL libraries.
如果您的 API 级别 >= 11,您可以通过在 Android 清单文件中添加以下属性来启用 hardware acceleration:
<application android:hardwareAccelerated="true"/>
此 SO post - Enable hardware acceleration in Android app, targeting Honeycomb AND prior versions 还可以帮助您在启用硬件加速之前在清单中添加所需的属性。
抱歉,问题发布不当。事实证明,问题是由于我的 ListView 中有多种不同类型的布局。
因此,每种布局类型都由不同的 class 处理。我的 ListAdapter 将 getView() 调用传递给每种布局类型的不同处理程序 classes。例如,当布局是由 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,并创建动态视图。如果里面的每一项都不一样,使用ListView真的没有任何优势,而且回收视图无法重复使用。