5

Wir versuchen, ein Speicherleck auf der GoogleMap in unserer Android App zu finden, die in einem OOM nach etwa 40-50 Geräteumdrehungen endet. Die Karte wird um 3500 Marker gesetzt.Android Maps V2 Speicherleck LocationClientHelper

Die App hat eine minSDK von 9 und verwendet daher das SupportMapFragment aus der V4 Support Library.

wir versucht haben, mehrere Dinge wie:

  • der
  • Caching CameraUpdates
  • Entfernen Markierungen aus der Karte
  • Entfernen von Hörern aus Karte
  • Entfernen aller Zuhörer die LatLng Caching, Marker usw. so dass wir nur eine einfache Karte haben
  • Google Play Services-Bibliothek wird aktualisiert
  • 012 Unterstützung
  • Updating Bibliothek

das Speicherabbild in MAT Analyse zeigt, dass wir viele Fälle von com.google.android.gms.location.internal.LocationClientHelper$ListenerTransport akkumulieren, die wir keine Ahnung haben, wo sie herkommen.

Jeder hat eine Idee, was könnte die Ursache für dieses Speicherleck sein?

Der folgende Code hat bereits alle markes und Listeners entfernt und noch Lecks. Zunächst wird die Basisklasse:

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

} 

Subclass

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

Ist dies möglicherweise ein Speicherverlust in einer der Google-Klassen? – byemute

+0

Google Maps-Problem wurde geöffnet: 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

Antwort

9

Ich hatte ein ähnliches Problem vor. Ich habe folgenden Code mein Problem zu lösen:

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

Es scheint, dass LocationClientHelper $ ListenerTransport zu setMyLocationEnabled() verwandt ist. Ich musste einige Callbacks abmelden, um Speicherlecks zu vermeiden.

+1

Sie, mein Freund, verdienen eine Medaille! Vielen Dank! Darüber hinaus haben wir die Listener, die auf der Karte festgelegt sind, ungültig gemacht und es scheint, das Problem zu lösen! – SOERGI

+1

Alter, du bist großartig! Würde Ihnen dafür Hunderte von Upvotes geben! Wir werden dies auch bei Google melden, da dies wirklich seltsam ist! – byemute

+1

Vielen Dank für das Teilen! Dies behebt endlich das Leck! Sie verdienen eine Umarmung von uns :) – byemute