Google地图精简版模式会在RecyclerView中引起混乱
我有一个RecyclerView
这是一个项目的垂直滚动列表。 每个列表项都包含Lite模式下的Google Maps V2 MapView。 我正在利用这个新function,它返回位图,而不是一个完整的地图作为Google Static Maps API
的替代品。
MapView要求您从父Activity / Fragment的相应方法调用onCreate()
, onResume()
, onPause()
, onDestroy()
等。 从RecyclerView.Adapter
和/或RecyclerView.ViewHolder
哪里可以调用这些地方?
我如何清理回收的MapViews,使内存不泄漏,同时保持清单免费?
谷歌说精简模式可以在列表中使用:
…'精简模式'的地图选项,非常适合您想要提供一些较小的地图的情况下,或者一个非常小的地图,以至于有意义的交互是不切实际的,比如列表中的缩略图。
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
更新date:(2016年2月3日) Google发布了一个在ListView中使用Lite Maps的代码示例。 看这里
解决scheme如下:
- 在
ViewHolder
类中实现OnMapReadyCallback
。 - 在
onMapReady
,调用MapsInitializer.initialize
,可以在获取地图之前使用MapsInitializer.initialize
function。
如果在获取地图之前需要使用function,请使用此类来初始化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(...); ... ... } } }
查找Google Maps Android API精简版模式示例 ( 源代码 )
你需要有一个单独的视图持有人类。 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类中被调用。
请按照本教程获得完整的概述。
Google说:
在完全交互模式下使用API时,MapView类的用户必须将所有活动生命周期方法转发给MapView类中的相应方法。 生命周期方法的例子包括onCreate(),onDestroy(),onResume()和onPause()。
在lite模式下使用MapView类时,转发生命周期事件是可选的,除了以下情况:
调用onCreate()是强制的,否则不会出现地图。 如果您希望在精简模式映射中显示“我的位置”点,并使用默认的位置源,则需要调用onResume()和onPause(),因为位置源将仅在这些调用之间进行更新。 如果您使用自己的位置来源,则无需调用这两种方法。
所以在lite模式下,您不必担心onDestroy(),onResume()和onPause()
我已经删除了这个Override方法,因为每次在testing时这会给出空的映射,并且它在我的recyclerView中完美地工作。
@Override public void onViewRecycled(ViewHolder holder) { // Cleanup MapView here? if (holder.gMap != null) { holder.gMap.clear(); holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE); } }
如果上面的代码在你的情况下不起作用,你可以试试。