Google 地图 Lite 模式导致 RecyclerView 出现卡顿

问题描述 投票:0回答:6

我有一个

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

MapView 要求您从父 Activity/Fragment 的相应方法中调用

onCreate()
onResume()
onPause()
onDestroy()
等。从
RecyclerView.Adapter
和/或
RecyclerView.ViewHolder
调用这些的正确位置在哪里?

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

Google 表示 Lite 模式可用于列表:

...“精简模式”地图选项,非常适合您想要的情况 提供一些较小的地图,或者一张很小的地图 有意义的交互是不切实际的,例如列表中的缩略图。

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 中使用 Lite Maps 的代码示例。 看这里

android google-maps android-recyclerview google-play-services google-maps-lite
6个回答
30
投票

解决方法如下:

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

如果在获取地图之前需要使用功能,请使用此类来初始化 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(...);

                  ... ...
         }

       }
    } 

5
投票

谷歌说:

以全交互方式使用API时,MapView类的用户必须将所有的Activity生命周期方法转发给MapView类中相应的方法。生命周期方法的示例包括 onCreate()、onDestroy()、onResume() 和 onPause()。

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

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

因此,在精简模式下,您不必担心 onDestroy()、onResume() 和 onPause()



3
投票

谷歌地图提供

Lite Mode

Android 版 Maps SDK 可以提供地图的位图图像,为用户提供有限的交互性。这称为精简模式地图。

精简模式

按照

LiteListDemoActivity
: Displaying maps efficiently in ListViews using lite mode
示例进行操作。


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>

Activity 类中的 onCreate()、onDestroy() 会像往常一样被调用。

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


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

如果上面的代码也不适用于您的情况,您可以尝试一下。

© www.soinside.com 2019 - 2024. All rights reserved.