Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: LocationManager leak, even though removeUpdates is called

I have implemented a Fragment which I use to obtain the GPS location of the device. For some reason, I get a memory leak - even though I unregister the listener (as suggested in all posts concerning a memory leak for LocationManager). I'm still relatively new to Android, so it might be something totally silly.

public class GetLocationTask extends Fragment {

/**
 * Callback interface through which the fragment will report the
 * task's progress and results back to the Activity. Calling activity MUST implement this.
 */
public interface LocationCallbacks {
    void onLocationReceived(double latitude, double longitude);
}

/** The calling activity. */
private LocationCallbacks mCallbacks;

private LocationManager locationManager;
private LocationListener locationListener;

/** Create a new instance. */
public static GetLocationTask newInstance() {
    GetLocationTask f = new GetLocationTask();

    // Supply index input as an argument.
    Bundle args = new Bundle();
    f.setArguments(args);

    return f;
}

@Override
public void onAttach(Context activity) {
    super.onAttach(activity);
    if (activity instanceof LocationCallbacks) {
        mCallbacks = (LocationCallbacks) activity;
    } else {
        Log.w("GetLocationTask", "CALLING CLASS DOES NOT IMPLEMENT INTERFACE!");
    }
}

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

    locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
    locationListener = new LocationListener() {
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }

        public void onLocationChanged(Location location) {
            if (location != null) {
                double longitude = location.getLongitude();
                double latitude = location.getLatitude();

                locationManager.removeUpdates(locationListener);

                mCallbacks.onLocationReceived(latitude, longitude);
                Log.i("result", longitude +  "   >> " + latitude);
            } else {
                Log.i("waiting", "warming up still");
            }
        }
    };


    try {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 90, locationListener);
    } catch (SecurityException e) {
        Log.i("TODO", "TODO");
    }

}

@Override
public void onDestroy() {
    super.onDestroy();
    if (locationManager != null && locationListener != null) {
        locationManager.removeUpdates(locationListener);
    }
    locationListener = null;
    locationManager = null;
}

@Override
public void onDetach() {
    super.onDetach();
    mCallbacks = null;
}
}
like image 334
Zee Avatar asked Apr 10 '26 10:04

Zee


1 Answers

You can prevent the memory leak by not having the locationListener have a reference to anything fragment related.

You create the LocationListener as an anonymous class and it therefore has a reference to your fragment and it also directly references mCallbacks which is a property of the fragment.

Define the locationListener as a separate class that you just instantiate in your fragment and then either pass a callback interface to the listener class as a constructor parameter or, possibly even better, observe a LiveData instance on your locationlistener (obviously observing using the fragment's lifecycleOwner).

like image 174
jhavatar Avatar answered Apr 12 '26 00:04

jhavatar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!