studio - google maps in fragment android
El modo Google Maps Lite causa jank en RecyclerView (5)
Encuentre el ejemplo de Google Maps Android API Lite Mode ( código fuente )
Tengo un RecyclerView
que es una lista de elementos de desplazamiento vertical. Cada elemento de la lista contiene un MapView de Google Maps V2 en modo básico. Aprovecho esta nueva función que devuelve mapas de bits en lugar de un mapa completo como reemplazo de la Google Static Maps API
.
MapView requiere que llame onCreate()
, onResume()
, onPause()
, onDestroy()
etc. desde el método correspondiente de onDestroy()
Activity / Fragment. ¿Dónde está el lugar adecuado para llamarlos desde RecyclerView.Adapter
y / o RecyclerView.ViewHolder
?
¿Cómo puedo limpiar MapViews reciclados para que no se filtre la memoria y mantener la lista libre?
Google dice que el modo básico se puede usar en listas:
... opción de mapa ''modo lite'', ideal para situaciones en las que desea proporcionar un número de mapas más pequeños, o un mapa que es tan pequeño que la interacción significativa no es práctica, como una miniatura en una lista.
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 y 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
Actualización: (8 de junio de 2018) Google lanzó una muestra de código para usar Lite Maps en un ListView. Mira aquí
Google dice:
Al utilizar la API en modo totalmente interactivo, los usuarios de la clase MapView deben reenviar todos los métodos del ciclo de vida de la actividad a los métodos correspondientes en la clase MapView. Los ejemplos de los métodos del ciclo de vida incluyen onCreate (), onDestroy (), onResume () y onPause ().
Cuando se usa la clase MapView en modo lite, el reenvío de los eventos del ciclo de vida es opcional, excepto en las siguientes situaciones:
Es obligatorio llamar a Crear (); de lo contrario, no aparecerá ningún mapa. Si desea mostrar el punto de Mi ubicación en su mapa del modo lite y usar el origen de ubicación predeterminado, deberá llamar a Repetición () y a Pausa (), ya que el origen de la ubicación solo se actualizará entre estas llamadas. Si usa su propia fuente de ubicación, no es necesario llamar a estos dos métodos.
Entonces, en el modo lite no tienes que preocuparte por onDestroy (), onResume () y onPause ()
He eliminado este método de anulación porque cada vez que esto da un mapa vacío cuando se prueba y funciona perfectamente en mi recyclerView.
@Override
public void onViewRecycled(ViewHolder holder)
{
// Cleanup MapView here?
if (holder.gMap != null)
{
holder.gMap.clear();
holder.gMap.setMapType(GoogleMap.MAP_TYPE_NONE);
}
}
Puedes probarlo si el código anterior tampoco funciona en tu caso.
Necesita tener una clase de Titular de Vista por separado. La clase RecyclerView Adapter solo tendrá onCreateViewHolder () y onBindViewHolder ().
Su archivo de diseño debe tener un aspecto similar a este:
<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>
Y se llamará a onCreate (), onDestroy () en la clase Activity como de costumbre.
Siga este tutorial para obtener una descripción completa.
Solución de la siguiente manera:
- Implementar
OnMapReadyCallback
en la claseViewHolder
. - En
onMapReady
, llame aMapsInitializer.initialize
paraMapsInitializer.initialize
que las características se puedan usar antes de obtener un mapa.
Utilice esta clase para inicializar la API de Android de Google Maps si las funciones deben ser utilizadas antes de obtener un mapa. Se debe invocar porque algunas clases como BitmapDescriptorFactory y CameraUpdateFactory deben inicializarse.
- Reciclar el mapa de
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(...);
... ...
}
}
}