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

时间:2015-02-19 17:21:19

标签: android google-maps android-recyclerview google-play-services google-maps-lite

我有一个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

6 个答案:

答案 0 :(得分:26)

解决方案如下:

  1. OnMapReadyCallback课程中实施ViewHolder
  2. onMapReady中,拨打MapsInitializer.initialize,可以在获取地图之前使用gaurantee功能。
  3.   

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

    1. onViewRecycled回收地图。

    2.     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可以提供地图的位图图像,从而为用户提供有限的交互性。这称为精简模式图。

Lite Mode

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

如果以上代码在您的情况下也不起作用,您可以尝试。