FusedLocationProviderClient.removeLocationUpdates always returns a failure

I have an activity that extends a class base called LocationAwareActivity , all this LocationAwareActivity activity does, creates a location service client

LocationServices.getFusedLocationProviderClient and listens before updating the location.

The source for this action is here https://github.com/snijsure/MultiActivity/blob/master/app/src/main/java/com/example/subodhnijsure/multiactivity/LocationAwareActivity.java

And when the action is destroyed, it calls removeLocationUpdates . I am

  • removeLocationUpdate returns a task that always returns non-successfully
  • More that location actions are not deleted, activity does not receive garbage collection.

enter image description here - Therefore, if I start any activity that inherits from LocationAwareActivity , that activity always remains on the heap.

So the question is what is the right way to stop receiving location updates, thereby allowing activity to collect garbage.

Here you can access the entire source for this project - https://github.com/snijsure/MultiActivity

+8
java android android-location
source share
4 answers

The reason the Task object returns false is in your stopLocationUpdates method, you create the local link **LocationCallback** again, and then use this link as an argument in locationProviderClient.removeLocationUpdates(cL); where the local LocationCallBack is never present in locationProviderClient

So what you need to do, instead of creating another LocationCallBack object, you must pass the same global object that you create in your startLocationUpdates method

your code should look like this

 inal Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback); 
+3
source share

In removeLocationUpdates you should pass locationCallback , the current implementation is incorrect.

However, there is a chance of a memory leak somewhere else. You should try to integrate Leakcanary into your application, and it can give you a link tree and tell you which field or listener is causing a memory leak. You can only link to one of my blog posts on a blog

 public void stopLocationUpdates() { if (locationProviderClient != null) { try { final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback); if (voidTask.isSuccessful()) { Log.d(TAG,"StopLocation updates successful! "); } else { Log.d(TAG,"StopLocation updates unsuccessful! " + voidTask.toString()); } } catch (SecurityException exp) { Log.d(TAG, " Security exception while removeLocationUpdates"); } } } 
+3
source share

Having studied the code in the repository, I found some problems in your design that could lead to the leak of your Activity .

1) You are using two different LocationCallbacks . One at the beginning and one in the stop method, but you should actually use the same. Thus, one instance of the instance will be sufficient and will probably lead to the successful result of your Task when deleting the LocationCallback .

2) Since you instantiate the LocationCallback twice with the Anonymous Class , you keep non-static references for the inner class, even if you end the class that calls your Memory Leak . You can read about it here .

3) IMHO it is better to use a separate manager class to process your location requests than to abstract the Activity .

It says that I ...

Decision

GpsManager.java

 public class GpsManager extends LocationCallback { private FusedLocationProviderClient client; private Callback callback; public interface Callback { void onLocationResult(LocationResult locationResult); } public boolean start(Context context, Callback callback) { this.callback = callback; client = LocationServices.getFusedLocationProviderClient(context); if (!checkLocationPermission(context)) return false; client.requestLocationUpdates(getLocationRequest(), this, null); return true; } public void stop() { client.removeLocationUpdates(this); } @Override public void onLocationResult(LocationResult locationResult) { callback.onLocationResult(locationResult); } private boolean checkLocationPermission(Context context) { int permissionCheck = ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION); return permissionCheck == PackageManager.PERMISSION_GRANTED; } private LocationRequest getLocationRequest() { return LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval(30_000L) .setFastestInterval(20_000L); } } 

and calling it from your Activity as follows

YourActivity.java

 public class MapsActivity extends AppCompatActivity implements GpsManager.Callback { private static final int PERMISSION_REQUEST_FINE_LOCATION = 1; private GpsManager mGpsManager; @Override protected void onCreate(Bundle savedInstanceState) { ... mGpsManager = new GpsManager(getApplicationContext(), this); // check if user gave permissions, otherwise ask via dialog if (!checkPermission()) { getLocationPermissions(); return; } mGpsManager.start(); ... } @Override protected void onStop() { super.onStop(); mGpsManager.stop(); } @Override public void onLocationResult(LocationResult locationResult) { // do something with the locationResult } // CHECK PERMISSIONS PART private boolean checkPermission() { return isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION)) && isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION)); } @TargetApi(Build.VERSION_CODES.M) private void getLocationPermissions() { requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_FINE_LOCATION); } @Override public void onRequestPermissionsResult(int code, @Nullable String permissions[], @Nullable int[] results) { switch (code) { case PERMISSION_REQUEST_FINE_LOCATION: if (isPermissionGranted(results)) { getLocationRequest(); } } } private boolean isPermissionGranted(int[] results) { return results != null && results.length > 0 && isGranted(results[0]); } private boolean isGranted(int permission) { return permission == PackageManager.PERMISSION_GRANTED; } } 

This is just an assumption because I have not tried your code, but the solution should help you anyway. Please correct me if I am wrong;)

+3
source share

Hi @Subodh Nijsure Please check the code below and paste it into your code and after checking it:

 final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback); voidTask.addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { Log.e(TAG, "addOnCompleteListener: "+task.isComplete()); } }); voidTask.addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Log.e(TAG, "addOnSuccessListener: " ); } }); voidTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "addOnFailureListener: "); } }); 

I think that voidTask.isSuccessful () this method does not work when you put this listener while it is working fine, and I also see in memory that it frees all memory when it comes to the previous action.

And when you are redirected to some action, please stopLocationUpdates () is called once in onPause () and removed from another method, for example onDestroy (), onStop (), because it stops once, so why should we call several time.

Hope this helps you.

+2
source share

All Articles