Google Maps Lite Mode 导致 RecyclerView 卡顿 [英] Google Maps Lite Mode causes jank in RecyclerView

查看:17
本文介绍了Google Maps Lite Mode 导致 RecyclerView 卡顿的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 RecyclerView,它是一个垂直滚动的项目列表.每个列表项都包含 Lite 模式.我正在利用这个新功能,它返回位图而不是完整的地图,作为 Google 静态地图 API 的替代品.

MapView 要求您调用 onCreate()onResume()onPause()onDestroy() 等来自父 Activity/Fragment 的相应的方法.从 RecyclerView.Adapter 和/或 RecyclerView.ViewHolder 调用这些的正确位置在哪里?

如何清理回收的 MapViews 以便内存不会泄漏,同时保持列表无卡顿?

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.MapViewandroid:id="@+id/mapImageView"xmlns:map="http://schemas.android.com/apk/res-auto"android:layout_width="80dp"android:layout_height="100dp"地图:liteMode =真"地图:地图类型=正常"地图:cameraZoom="15"/><!-- ... --></RelativeLayout>

RecyclerView.Adapter 和 ViewHolder

public class NearbyStopsAdapter extends RecyclerView.Adapter{私有最终上下文 mContext;公共类 ViewHolder 扩展 RecyclerView.ViewHolder 实现 View.OnClickListener {地图查看地图;公共 ViewHolder(查看视图){超级(查看);map = (MapView) view.findViewById(R.id.mapImageView);//应该在这里创建吗?map.onCreate(null);map.onResume();}}公共 NearbyStopsAdapter(上下文 c){this.mContext = c;}@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {查看 itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_nearby_stop, viewGroup, false);返回新的 ViewHolder(itemView);}@Override public void onBindViewHolder(ViewHolder holder, int position) {//在这里调用异步映射?holder.map.getMapAsync(this);}@Override public void onViewRecycled(ViewHolder holder) {//在这里清理 MapView?//if (holder.map != null) {//holder.map.onPause();//holder.map.onDestroy();//}}@Override public void onViewAttachedToWindow(ViewHolder holder) {//在这里设置 MapView?//holder.map.onCreate(null);//holder.map.onResume();}@Override public void onViewDetachedFromWindow(ViewHolder holder) {//在这里清理 MapView?//if (holder.map != null) {//holder.map.onPause();//holder.map.onDestroy();//}}//...}

Logcat:

I/Google Maps Android API:Google Play 服务包版本:659943W/Google Maps Android API: Lite 模式不支持 Map Loaded 回调W/Google Maps Android API:Lite 模式不支持建筑物W/Google Maps Android API:在精简模式下不支持室内W/Google Maps Android API:精简模式不支持切换手势W/Google Maps Android API:精简模式不支持切换手势W/Google Maps Android API:精简模式不支持切换手势W/Google Maps Android API:精简模式不支持切换手势

更新:(2018 年 6 月 8 日) Google 发布了在 ListView 中使用 Lite Maps 的代码示例.看这里

解决方案

解决方案如下:

  1. ViewHolder 类中实现OnMapReadyCallback.
  2. onMapReady中,调用MapsInitializer.initialize,保证在获取地图之前可以使用特征.

<块引用>

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

  1. onViewRecycled 回收地图.


 public class NearbyStopsAdapter extends RecyclerView.Adapter{@覆盖public void onBindViewHolder(ViewHolder holder, int position){//从数据列表中通过位置"获取位置"//获取谷歌地图GoogleMap thisMap = holder.gMap;//然后将地图移动到位置"if(thisMap != null)//将地图移动到位置"thisMap.moveCamera(...);}//为列表项回收GoogleMap@覆盖public void onViewRecycled(ViewHolder holder){//在这里清理 MapView?if (holder.gMap != null){holder.gMap.clear();holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE);}}公共类 ViewHolder 扩展 RecyclerView.ViewHolder 实现 OnMapReadyCallback {谷歌地图 gMap;地图查看地图;……公共 ViewHolder(查看视图){超级(查看);map = (MapView) view.findViewById(R.id.mapImageView);如果(地图!= null){map.onCreate(null);map.onResume();map.getMapAsync(this);}}@覆盖公共无效 onMapReady(GoogleMap googleMap) {//如果在获取地图之前需要使用功能,则初始化Google Maps Android APIMapsInitializer.initialize(getApplicationContext());gMap = 谷歌地图;//您可以将这里的地图移动到项目特定的位置"int pos = getPosition();//从数据列表中通过'pos'获取'location'//然后移动到'位置'gMap.moveCamera(...);……}}}

I have a RecyclerView which is a vertical scrolling list of items. Each list item contains a Google Maps V2 MapView in Lite Mode. I'm taking advantage of this new feature which returns bitmaps instead of a full-blown map as a replacement to the Google Static Maps API.

MapView requires that you call onCreate(), onResume(), onPause(), onDestroy() etc. from the parent Activity/Fragment's corresponding method. Where is the proper place to call these from the RecyclerView.Adapter and/or RecyclerView.ViewHolder?

How can I clean up recycled MapViews so that memory doesn't leak, while keeping the list jank free?

Google says Lite Mode can be used in lists:

... ‘lite mode’ map option, ideal for situations where you want to provide a number of smaller maps, or a map that is so small that meaningful interaction is impractical, such as a thumbnail in a list.

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 and 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

Update: (Jun 8, 2018) Google has released a code sample for using Lite Maps in a ListView. See here

解决方案

Solution as following:

  1. Implement OnMapReadyCallback in ViewHolder class.
  2. In onMapReady, call MapsInitializer.initialize, to gaurantee features can to be used before obtaining a map.

Use this class to initialize the Google Maps Android API if features need to be used before obtaining a map. It must be called because some classes such as BitmapDescriptorFactory and CameraUpdateFactory need to be initialized.

  1. Recycle map from 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 Lite Mode 导致 RecyclerView 卡顿的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆