web-dev-qa-db-ja.com

Google Maps Liteモードにより、RecyclerViewがジャンクする

アイテムの垂直スクロールリストであるRecyclerViewがあります。各リストアイテムには、 Lite Mode のGoogle Maps V2 MapViewが含まれています。 _Google Static Maps API_の代わりとして、本格的なマップの代わりにビットマップを返すこの新しい機能を利用しています。

MapView では、親Activity /から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>
_

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は、Lite Mapsを使用するためのコードサンプルをリリースしましたリストビュー。 こちらを参照

42
Ryan R

次のような解決策:

  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(...);

                  ... ...
         }

       }
    } 
27
Xcihnegn

Googleによると:

APIを完全インタラクティブモードで使用する場合、MapViewクラスのユーザーは、すべてのアクティビティライフサイクルメソッドをMapViewクラスの対応するメソッドに転送する必要があります。ライフサイクルメソッドの例には、onCreate()、onDestroy()、onResume()、およびonPause()が含まれます。

ライトモードでMapViewクラスを使用する場合、ライフサイクルイベントの転送はオプションですが、次の状況を除きます。

OnCreate()の呼び出しは必須です。そうでない場合、マップは表示されません。ライトモードマップに現在地のドットを表示し、デフォルトのロケーションソースを使用する場合は、onResume()およびonPause()を呼び出す必要があります。ロケーションソースはこれらの呼び出し間でのみ更新されるためです。独自のロケーションソースを使用する場合、これらの2つのメソッドを呼び出す必要はありません。

したがって、Liteモードでは、onDestroy()、onResume()、onPause()を心配する必要はありません。

5
bjarocki
3

GoogleマップはLite Mode

AndroidのMaps SDKは、マップのビットマップ画像を提供でき、ユーザーに限られたインタラクティブ性を提供します。これはライトモードマップと呼ばれます。

ライトモード

LiteListDemoActivity: Displaying maps efficiently in ListViews using lite mode例。

2
Kasim Rangwala

テスト時に空のマップが表示され、recyclerViewで完全に機能するため、このオーバーライドメソッドを削除しました。

@Override 
public void onViewRecycled(ViewHolder holder) 
{
  // Cleanup MapView here?
  if (holder.gMap != null) 
  {
      holder.gMap.clear();
      holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE);
  }
}

上記のコードがあなたの場合にも動作しない場合は、それを試すことができます。

0
Suman Bakhati

別のビューホルダークラスが必要です。 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 に従ってください。

0
AniV