0

I started using Leak Canary and I get this memory leak after rotation fragment with MapView on it.

10-04 22:01:51.530 17969-18044/cz.united121.android.revizori I/art: hprof: heap dump "/storage/emulated/0/Download/leakcanary/suspected_leak_heapdump.hprof" starting...
10-04 22:02:30.872 17969-20755/cz.united121.android.revizori D/LeakCanary: In cz.united121.android.revizori:1.0:1.
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * cz.united121.android.revizori.activity.MapActivity has leaked:
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * GC ROOT com.google.android.gms.location.internal.f.a
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.android.gms.location.internal.e.h
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.d.w.e
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.d.ak.b
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.gmm6.c.p.a
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.gmm6.c.y.mParent
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references android.widget.FrameLayout.mParent
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.android.gms.maps.MapView.mContext
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * leaks cz.united121.android.revizori.activity.MapActivity instance
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Reference Key: 58a52845-81c4-4562-a45c-c831a92629c3
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Device: motorola motorola XT1032 falcon_tescogbsl
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Android Version: 5.0.2 API: 21 LeakCanary: 1.3.1

this is how I adding fragment to activity (I am calling this in onCreate in activity and after selecting item in Navigation menu) it uses simply principles that the fragment is not destroyed but only cover the map fragment - I dont have to take care about retain state:

public void changeFragment(String toFragment, Bundle args){
    Log.d(TAG, "changeFragment");
    Util.hideSoftKeyboard(this);
    Fragment fragment = null;
    String backStateName =  toFragment;

    Fragment mCurrentFragment = getFragmentManager().findFragmentById(R.id
            .fragment_place);

    if(mCurrentFragment == null){
        fragment = instantiateFragment(toFragment,args);
        getFragmentManager().beginTransaction()
                .setCustomAnimations(
                        R.animator.fragment_slide_in, R.animator.fragment_slide_out, 0, 0)
                .add(R.id.fragment_place, fragment, backStateName)
                .addToBackStack(backStateName)
                .commit();
        return;
    }

    if(mCurrentFragment.getClass().getName().equals(toFragment)){
        return;
    }

    boolean fragmentPopped = getFragmentManager().popBackStackImmediate(backStateName, 0);

    if (!fragmentPopped && getFragmentManager().findFragmentByTag(backStateName) == null){ //fragment not in back stack, create it.
        fragment = instantiateFragment(toFragment,args);
        getFragmentManager().beginTransaction()
                .setCustomAnimations(
                        R.animator.fragment_slide_in, R.animator.fragment_slide_out, 0, 0)
                .add(R.id.fragment_place, fragment, backStateName)
                .addToBackStack(backStateName)
                .commit();
    }
}

and fragment code

public static final String KEY_POINTS = "points";
private final static String BUNDLE_KEY_MAP_STATE = "mapData";

@Bind(R.id.map)
MapView mMapView;
GoogleMap mMap;

private static int PERIOD_BETWEEN_REPORTING = 10 * 1000; // ms
private static boolean isTimeValid = true;
private static MyCountingThread mThread;

public static TestMapFragment newInstance() {
    TestMapFragment fragment = new TestMapFragment();

    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView");
    View mapLayout = inflater.inflate(R.layout.fragment_map, container, false);
    ButterKnife.bind(this, mapLayout);

    Bundle mapState = null;
    if (savedInstanceState != null) {
        // Load the map state bundle from the main savedInstanceState
        mapState = savedInstanceState.getBundle(BUNDLE_KEY_MAP_STATE);
    }

    mMapView.onCreate(mapState);


    return mapLayout;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    Log.d(TAG, "onSaveInstanceState");
    // Save the map state to it's own bundle
    Bundle mapState = new Bundle();
    mMapView.onSaveInstanceState(mapState);
    // Put the map bundle in the main outState
    outState.putBundle(BUNDLE_KEY_MAP_STATE, mapState);
    super.onSaveInstanceState(outState);
}


@Override
public void onActivityCreated(Bundle savedInstanceState) {
    Log.d(TAG, "onActivityCreated");
    super.onActivityCreated(savedInstanceState);
}

@Override
public void onPause() {
    Log.d(TAG, "onPause");
    mMapView.onPause();
    super.onPause();
    //mMap = null;
}

@Override
public void onResume() {
    Log.d(TAG, "onResume");
    super.onResume();
    setUpMapIfNeeded();
    mMapView.onResume();
}

@Override
public void onDestroyView() {
    super.onDestroyView();

    Log.d(TAG, "onDestroyView");
}

@Override
public void onStop() {
    super.onStop();
    if (BuildConfig.DEBUG) {
        Log.d(TAG, "onStop");
    }
}

@Override
public void onDestroy() {
    Log.d(TAG, "onDestroy");
    mMapView.onDestroy();
    mMap = null;
    ButterKnife.unbind(this);
    super.onDestroy();
}

public void onLowMemory() {
    Log.d(TAG, "onLowMemory");
    super.onLowMemory();
    mMapView.onLowMemory();
}

;

private void setUpMapIfNeeded() {
    Log.d(TAG, "setUpMapIfNeeded");
    if (mMap == null) {
        mMapView.getMapAsync(this);
    }
}


@Override
public void onMapReady(GoogleMap googleMap) {
    Log.d(TAG, "onMapReady");
    mMap = googleMap;

    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setZoomControlsEnabled(true);

    mMap.setOnMapClickListener(this);
    mMap.setOnCameraChangeListener(this);

    refreshMap();

    CameraPosition lastCameraPosition = TestGetterLocation.getCameraPosition();
    if(lastCameraPosition != null){
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(lastCameraPosition.target, lastCameraPosition.zoom));
    }
}

@Override
public void onMapClick(LatLng latLng) {
    Log.d(TAG, "onMapClick");
    //mMap.addMarker(new MarkerOptions().position(latLng));
    //TestGetterLocation.addLocationMarker(latLng);

    LocationGetter.addReport(new ReportInspector(ParseUser.getCurrentUser(), new ParseGeoPoint(latLng.latitude,latLng.longitude), TypeOfVehicle.BUS.name()));
}

@Override
public void onCameraChange(CameraPosition cameraPosition) {
    Log.d(TAG, "onCameraChange");
    TestGetterLocation.setCameraPosition(cameraPosition);
}

@OnClick(R.id.reporting_insperctor)
public void OnReportinInspectorClick(View view){
    refreshMap();
}

private void refreshMap(){
    mMap.clear();

    for (ReportInspector report : LocationGetter.getReports()) {
        mMap.addMarker(new MarkerOptions()
                .position(report.getLocation())
                .icon(BitmapDescriptorFactory.fromResource(report
                        .getTypeOfVehicle()
                        .getMarkerImageResource())));
    }
}

any idea why is memory leak happen ?

United121
  • 729
  • 1
  • 10
  • 24

1 Answers1

0

After some gooling I found that this is known issue and try solution from this page https://code.google.com/p/gmaps-api-issues/issues/detail?id=8111 and LeakCanary isnt reportin memory leak anymore.

United121
  • 729
  • 1
  • 10
  • 24