我有一个RecyclerView
,它是一个垂直滚动的项目列表。每个列表项都包含Lite Mode中的Google Maps V2 MapView。我正在利用这个新功能返回位图而不是完整的地图作为Google Static Maps API
的替代。
MapView要求您从父级Activity / Fragment的相应方法中调用onCreate()
,onResume()
,onPause()
,onDestroy()
等。从RecyclerView.Adapter
和/或RecyclerView.ViewHolder
如何清理回收的MapView以便内存不会泄漏,同时保持列表清空?
Google says Lite Mode can be used in lists:
...'精简模式'地图选项,适合您想要的情况 提供一些较小的地图,或一个如此小的地图 有意义的互动是不切实际的,例如列表中的缩略图。
ListItem.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.gms.maps.MapView
android:id="@+id/mapImageView"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="80dp"
android:layout_height="100dp"
map:liteMode="true"
map:mapType="normal"
map:cameraZoom="15"/>
<!-- ... -->
</RelativeLayout>
RecyclerView.Adapter和ViewHolder
public class NearbyStopsAdapter extends RecyclerView.Adapter<NearbyStopsAdapter.ViewHolder> {
private final Context mContext;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
MapView map;
public ViewHolder(View view) {
super(view);
map = (MapView) view.findViewById(R.id.mapImageView);
// Should this be created here?
map.onCreate(null);
map.onResume();
}
}
public NearbyStopsAdapter(Context c) {
this.mContext = c;
}
@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_nearby_stop, viewGroup, false);
return new ViewHolder(itemView);
}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
//Call Async Map here?
holder.map.getMapAsync(this);
}
@Override public void onViewRecycled(ViewHolder holder) {
// Cleanup MapView here?
// if (holder.map != null) {
// holder.map.onPause();
// holder.map.onDestroy();
// }
}
@Override public void onViewAttachedToWindow(ViewHolder holder) {
// Setup MapView here?
// holder.map.onCreate(null);
// holder.map.onResume();
}
@Override public void onViewDetachedFromWindow(ViewHolder holder) {
// Cleanup MapView here?
// if (holder.map != null) {
// holder.map.onPause();
// holder.map.onDestroy();
// }
}
// ...
}
logcat的:
I/Google Maps Android API﹕ Google Play services package version: 659943
W/Google Maps Android API﹕ Map Loaded callback is not supported in Lite Mode
W/Google Maps Android API﹕ Buildings are not supported in Lite Mode
W/Google Maps Android API﹕ Indoor is not supported in Lite Mode
W/Google Maps Android API﹕ Toggling gestures is not supported in Lite Mode
W/Google Maps Android API﹕ Toggling gestures is not supported in Lite Mode
W/Google Maps Android API﹕ Toggling gestures is not supported in Lite Mode
W/Google Maps Android API﹕ Toggling gestures is not supported in Lite Mode
更新:(2018年6月8日) Google发布了在ListView中使用精简版地图的代码示例。 See here
答案 0 :(得分:26)
解决方案如下:
OnMapReadyCallback
课程中实施ViewHolder
。onMapReady
中,拨打MapsInitializer.initialize
,可以在获取地图之前使用gaurantee功能。如果在获取地图之前需要使用功能,请使用此类初始化Google Maps Android API。必须调用它,因为需要初始化一些类,如BitmapDescriptorFactory和CameraUpdateFactory。
onViewRecycled
回收地图。
public class NearbyStopsAdapter extends RecyclerView.Adapter<NearbyStopsAdapter.ViewHolder> {
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
//get 'location' by 'position' from data list
//get GoogleMap
GoogleMap thisMap = holder.gMap;
//then move map to 'location'
if(thisMap != null)
//move map to the 'location'
thisMap.moveCamera(...);
}
//Recycling GoogleMap for list item
@Override
public void onViewRecycled(ViewHolder holder)
{
// Cleanup MapView here?
if (holder.gMap != null)
{
holder.gMap.clear();
holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE);
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements OnMapReadyCallback {
GoogleMap gMap;
MapView map;
... ...
public ViewHolder(View view) {
super(view);
map = (MapView) view.findViewById(R.id.mapImageView);
if (map != null)
{
map.onCreate(null);
map.onResume();
map.getMapAsync(this);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
//initialize the Google Maps Android API if features need to be used before obtaining a map
MapsInitializer.initialize(getApplicationContext());
gMap = googleMap;
//you can move map here to item specific 'location'
int pos = getPosition();
//get 'location' by 'pos' from data list
//then move to 'location'
gMap.moveCamera(...);
... ...
}
}
}
答案 1 :(得分:5)
在完全交互模式下使用API时,MapView类的用户必须将所有活动生命周期方法转发到MapView类中的相应方法。生命周期方法的示例包括onCreate(),onDestroy(),onResume()和onPause()。
在精简版模式下使用MapView类时,转发生命周期事件是可选的,但以下情况除外:
必须调用onCreate(),否则不会显示地图。 如果您希望在精简模式映射上显示“我的位置”点并使用默认位置源,则需要调用onResume()和onPause(),因为位置源只会在这些调用之间进行更新。如果您使用自己的位置来源,则无需调用这两种方法。
所以在lite模式下你不必担心onDestroy(),onResume()和onPause()
答案 2 :(得分:3)
答案 3 :(得分:2)
Google地图提供了Lite Mode
Android版Maps SDK可以提供地图的位图图像,从而为用户提供有限的交互性。这称为精简模式图。
遵循LiteListDemoActivity
: Displaying maps efficiently in ListViews using lite mode
示例。
答案 4 :(得分:0)
您需要有一个单独的View Holder类。 RecyclerView Adapter类只有onCreateViewHolder()和onBindViewHolder()。
您的布局文件应该与此类似:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity">
<view
<com.google.android.gms.maps.MapView
android:id="@+id/mapImageView"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="80dp"
android:layout_height="100dp"
map:liteMode="true"
map:mapType="normal"
map:cameraZoom="15" />
</RelativeLayout>
onCreate(),onDestroy()将像往常一样在Activity类中调用。
请按照此tutorial获取完整概述。
答案 5 :(得分:0)
我删除了这个Override方法,因为每次测试时它都会给出空地图,并且它在我的recyclerView中完美运行。
@Override
public void onViewRecycled(ViewHolder holder)
{
// Cleanup MapView here?
if (holder.gMap != null)
{
holder.gMap.clear();
holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE);
}
}
如果以上代码在您的情况下也不起作用,您可以尝试。