Google Maps Lite模式会在RecyclerView中导致jank

Rya*_*n R 42 android google-maps google-play-services android-recyclerview google-maps-lite

我有一个RecyclerView垂直滚动的项目列表.每个列表项都包含精简模式下的Google Maps V2 MapView .我正在利用这个新功能返回位图,而不是一个完整的地图作为替代Google Static Maps API.

MapView的需要你打电话onCreate(),onResume(),onPause(),onDestroy()等从父活动/片段的相应的方法.在哪里RecyclerView.Adapter和/或RecyclerView.ViewHolder

如何清理回收的MapView,以便内存不会泄漏,同时保持列表清空?

Google表示精简模式可用于列表:

...'精简模式'地图选项,非常适合您想要提供大量较小地图的情况,或者非常适合有意义的互动不切实际的地图,例如列表中的缩略图.

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>
Run Code Online (Sandbox Code Playgroud)

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();
//        }
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

更新:(2018年6月8日)谷歌发布了一个代码示例,用于在ListView中使用精简版地图.看这里

Xci*_*egn 27

解决方案如下:

  1. OnMapReadyCallbackViewHolder课堂上实施.
  2. 在获取地图之前,可以使用onMapReady,调用MapsInitializer.initializegaurantee功能.

如果在获取地图之前需要使用功能,请使用此类初始化Google Maps Android API.必须调用它,因为需要初始化一些类,如BitmapDescriptorFactory和CameraUpdateFactory.

  1. 从中回收地图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(...);

                  ... ...
         }

       }
    } 
Run Code Online (Sandbox Code Playgroud)

  • 这是我的适配器,它工作得很好,也许对你有用:https://gist.github.com/Yazon2006/5d7fd1716093441e3b25e088f9332cf8 (2认同)

小智 5

谷歌说:

在完全交互模式下使用API​​时,MapView类的用户必须将所有活动生命周期方法转发到MapView类中的相应方法.生命周期方法的示例包括onCreate(),onDestroy(),onResume()和onPause().

在精简模式下使用MapView类时,转发生命周期事件是可选的,但以下情况除外:

必须调用onCreate(),否则不会出现地图.如果您希望在精简模式映射上显示"我的位置"点并使用默认位置源,则需要调用onResume()和onPause(),因为位置源只会在这些调用之间进行更新.如果您使用自己的位置源,则无需调用这两种方法.

所以在lite模式下你不必担心onDestroy(),onResume()和onPause()


Ani*_*niV 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>
Run Code Online (Sandbox Code Playgroud)

而onCreate()、onDestroy()将照常在Activity类中调用。

请按照本教程获得完整的概述。