5

Stiamo cercando di rintracciare una perdita di memoria che si verifica su GoogleMap nella nostra app per Android, che termina in una OOM dopo circa 40-50 rotazioni del dispositivo. La mappa viene impostata intorno a 3500 indicatori.Perdita di memoria delle mappe Android V2 LocationClientHelper

L'app ha un minSDK di 9 e pertanto utilizza SupportMapFragment dalla libreria di supporto V4.

cose più

Abbiamo provato tra cui:

  • Caching del LatLng
  • Caching CameraUpdates
  • Rimozione marcatori dalla mappa
  • Rimozione ascoltatori dalla mappa
  • Rimuovere tutti gli ascoltatori, i marcatori, ecc in modo che abbiamo solo una mappa semplice
  • Aggiornamento della libreria di Google Play Services
  • Aggiornamento libreria di supporto

Analizzando il dump della memoria in MAT mostra che si accumulano un sacco di istanze di com.google.android.gms.location.internal.LocationClientHelper$ListenerTransport cui non abbiamo idea di dove essi sono provenienti da.

Qualcuno ha un'idea su quale potrebbe essere la causa di questa perdita di memoria?

Il seguente codice ha già tutti i contrassegni e gli ascoltatori rimossi e ancora perdite. In primo luogo la classe di base:

public abstract class BaseMapFragment extends Fragment { 

public static final int MENU_ITEM_ID_SEARCH= 102; 
public static final int MENU_ITEM_ID_SHOW_LIST= 100; 
public static final int ZOOM_LEVEL_DEFAULT= 14; 

private static final String SAVED_INSTANCE_LATITUDE= "savedLatitude"; 
private static final String SAVED_INSTANCE_LONGITUDE= "savedLongitutde"; 
private static final String SAVED_INSTANCE_ZOOM= "savedZoom"; 

protected static final String CLASSTAG= BaseMapFragment.class.getSimpleName(); 

private GoogleMap mMap; 
private CameraUpdate mResumeCameraUpdate= null; 
private double mSavedLatitude; 
private double mSavedLongitude; 
private float mSavedZoom; 
private static View mView; 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    if (mMap != null) { 
     outState.putDouble(SAVED_INSTANCE_LATITUDE, mMap.getCameraPosition().target.latitude); 
     outState.putDouble(SAVED_INSTANCE_LONGITUDE, mMap.getCameraPosition().target.longitude); 
     outState.putFloat(SAVED_INSTANCE_ZOOM, mMap.getCameraPosition().zoom); 
    } 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    super.onCreateView(inflater, container, savedInstanceState); 
    if (savedInstanceState != null) { 
     mSavedLatitude= savedInstanceState.getDouble(SAVED_INSTANCE_LATITUDE, Constants.EXTRA_VALUE_NONE); 
     mSavedLongitude= savedInstanceState.getDouble(SAVED_INSTANCE_LONGITUDE, Constants.EXTRA_VALUE_NONE); 
     mSavedZoom= savedInstanceState.getFloat(SAVED_INSTANCE_ZOOM, Constants.EXTRA_VALUE_NONE); 
    } 

    if (mView != null) { 
     ViewGroup parent= (ViewGroup) mView.getParent(); 
     if (parent != null) 
      parent.removeView(mView); 
    } 
    try { 
     mView= inflater.inflate(R.layout.map_layout, container, false); 
    } catch (InflateException e) { 
     /* map is already there, just return view as it is */ 
    } 
    return mView; 
} 

protected GoogleMap initializeMap() { 
    if (mMap != null) { 
     if (mSavedLatitude != Constants.EXTRA_VALUE_NONE && mSavedLatitude != 0.0) { 
      mResumeCameraUpdate= Context.getCamUpdate(mSavedZoom, mSavedLatitude, mSavedLongitude); 
     } else { 
      mResumeCameraUpdate= Context.getCamUpdate(mMap.getCameraPosition().zoom, mMap.getCameraPosition().target.latitude, mMap.getCameraPosition().target.longitude); 
     } 
    } 

    SupportMapFragment mapFragment= (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map); 
    if (mapFragment == null) { 
     mapFragment= (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map); 
     if (mapFragment == null) { 
      MapsInitializer.initialize(getActivity()); 
      mapFragment= SupportMapFragment.newInstance(); 
      mMap= mapFragment.getMap(); 
     } else { 
      mMap= mapFragment.getMap(); 
     } 
    } else { 
     mMap= mapFragment.getMap(); 
    } 

    // check if map is created successfully or not 
    if (mMap == null) { 
     Toast.makeText(getActivity().getApplicationContext(), R.string.map_create_unable, Toast.LENGTH_SHORT).show(); 
    } else { 
     mMap.setMyLocationEnabled(true); 
     mMap.setOnMyLocationButtonClickListener(new OnMyLocationButtonClickListener() { 
      @Override 
      public boolean onMyLocationButtonClick() { 
       if (mMap.getMyLocation() != null) { 
        CameraUpdate newLatLngZoom= Context.getCamUpdate(ZOOM_LEVEL_DEFAULT, mMap.getMyLocation()); 
        mMap.animateCamera(newLatLngZoom); 
       } else { 
        Toast.makeText(getActivity().getApplicationContext(), R.string.map_location_services_disabled, Toast.LENGTH_SHORT).show(); 
       } 
       return true; 
      } 
     }); 

    } 
    return mMap; 
} 

} 

sottoclasse

public class MySupportMapFragment extends BaseMapFragment { 

private LinearLayout mStaoButtonsLayout; 
private ToggleButton mStaoButton; 
private ToggleButton mGasStaoButton; 

private Boolean mInitialLocationChange; 
private CameraUpdate mResumeCameraUpdate; 
private GoogleMap mMap; 
private double mBundleLatitude; 
private double mBundleLongitude; 


@Override 
public void addRequiredModelClasses(LinkedHashSet<Class<? extends ComergeModel<?>>> set) { 
    set.add(AboModel.class); 
    set.add(StationModel.class); 
    super.addRequiredModelClasses(set); 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    outState.putDouble(BUNDLE_EXTRA_CENTER_LATITUDE, mBundleLatitude); 
    outState.putDouble(BUNDLE_EXTRA_CENTER_LONGITUDE, mBundleLongitude);   
} 


@Override 
public void onActivityCreated(final Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    setHasOptionsMenu(showSearchButton()); 

    final StationModel stationModel= getContext().getModel(StationModel.class); 

    mStaoButtonsLayout= (LinearLayout) getActivity().findViewById(R.id.mapStaoButtons); 
    mStaoButtonsLayout.setVisibility(View.VISIBLE); 
    mStaoButton= (ToggleButton) mStaoButtonsLayout.findViewById(R.id.staoButton); 
    mStaoButton.setChecked(stationModel.isStationButtonChecked()); 
    mGasStaoButton= (ToggleButton) mStaoButtonsLayout.findViewById(R.id.gasStaoButton); 
    mGasStaoButton.setChecked(stationModel.isGasStationButtonChecked()); 

    mMap= initializeMap(); 
} 

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    super.onCreateOptionsMenu(menu, inflater); 
    addSearchButton(menu); 
} 

} 
+0

Si tratta forse di una perdita di memoria in una delle classi di google? – byemute

+0

Problema di Google Maps aperto: https://code.google.com/p/gmaps-api-issues/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Introduced%20Fixed%20Summary% 20Stars% 20ApiType% 20Internal & groupby = & sort = & id = 8446 – byemute

risposta

9

Ho avuto un problema simile prima. Ho aggiunto seguente codice per risolvere il mio problema:

@Override 
public void onDestroy() { 
    if (mMap != null) { 
     mMap.setMyLocationEnabled(false); 
    } 
} 

Sembra che LocationClientHelper $ ListenerTransport è legato alla setMyLocationEnabled(). Ho dovuto annullare la registrazione di alcuni callback per evitare perdite di memoria.

+1

Tu amico mio, meriti una medaglia! Grazie! Inoltre, abbiamo annullato gli ascoltatori impostati sulla mappa e sembra aver risolto il problema! – SOERGI

+1

Amico, sei fantastico! Ti darei centinaia di voti per questo! Segnaleremo anche questo a google in quanto è rude strano! – byemute

+1

Grazie per aver condiviso questo! Questo finalmente risolve la perdita! Ti meriti un abbraccio da noi :) – byemute