18

I used to use FusedLocationApi until I learned that it is deprecated (see references below). It was simple to implement. As the documentation says you need to use it in conjunction with GoogleApiClient

LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient,
                        locationRequest, this);

I recently changed to FusedLocationProviderClient (see reference below) Following a tutorial I was able to successfully get FusedLocationProviderClient working

Tutorial: https://github.com/codepath/android_guides/wiki/Retrieving-Location-with-LocationServices-API

// new Google API SDK v11 uses getFusedLocationProviderClient(this)
getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, new LocationCallback() {
      @Override
      public void onLocationResult(LocationResult locationResult) {
         // do work here
         onLocationChanged(locationResult.getLastLocation();
      }
    },
    Looper.myLooper());

The issue I am running into is the Looper thread. Even with the application in the background, the Looper thread continues to run. I would like to pause location updates when the application is in the background and then resume location updates when the application is in the foreground. How can I achieve this?

References:

  1. https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
  2. https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient
portfoliobuilder
  • 7,556
  • 14
  • 76
  • 136

2 Answers2

36

You just need to call mFusedLocationClient.removeLocationUpdates(mLocationCallback) in onPause() of your Activity. However, there is a bit more to it than just that.

Use member variables for the FusedLocationProviderClient and LocationRequest in your main activity:

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;

public class MainActivity extends AppCompatActivity
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    FusedLocationProviderClient mFusedLocationClient;
    LocationRequest mLocationRequest;

    //..........

Use a member variable for the LocationCallback as well:

LocationCallback mLocationCallback = new LocationCallback(){
    @Override
    public void onLocationResult(LocationResult locationResult) {
        for (Location location : locationResult.getLocations()) {
            Log.i("MainActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());

        }
    };

};

Then, assign mFusedLocationClient in onCreate() :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    requestLocationUpdates();

    //...............
}

Then in onResume(), if theFusedLocationProviderClient is set up, then use it.

@Override
public void onResume() {
    if (mFusedLocationClient != null) {
        requestLocationUpdates();
    }
}

public void requestLocationUpdates() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(120000); // two minute interval
    mLocationRequest.setFastestInterval(120000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {
        mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
    }
}

And finally, in onPause(), call removeLocationUpdates():

@Override
public void onPause() {
    super.onPause();
    if (mFusedLocationClient != null) {
        mFusedLocationClient.removeLocationUpdates(mLocationCallback);
    }
}
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • @DanielNugent, if I have used this code in non-activity class but `mFusedLocationClient.removeLocationUpdates` not working. please check [this problem](https://stackoverflow.com/q/49644547/2264534) – immodi Apr 04 '18 at 07:27
  • 2
    Will it provide location updates even when there is no internet connection? – Vivek Bhardwaj Jul 04 '18 at 09:19
  • 4
    All the part of the "GoogleApiClient" can be removed. They are no more needed with FusedLocationProviderClient. Read https://developers.google.com/android/guides/api-client and https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApi – ARLabs May 10 '19 at 13:25
  • We will not get onLocationResult() callback when gps is turned off. – K Pradeep Kumar Reddy Apr 21 '20 at 08:11
  • @PradeepkumarReddy Yes, that is expected. If the Location setting is off, then you should prompt the user to turn on the setting. You can use a LocationSettingsRequest, see here: https://stackoverflow.com/questions/31235564/locationsettingsrequest-dialog-to-enable-gps-onactivityresult-skipped – Daniel Nugent Apr 21 '20 at 17:40
  • @Daniel Nugent, Can we call LocationSettingRequest from a foreground service ?? Because i'm requesting for location updates from a foreground serrvice. – K Pradeep Kumar Reddy May 03 '20 at 12:41
  • @Daniel Nugent, According to what i understood, LocationSettingRequest check is done only once before requesting for location updates right ?? After starting request for location updates, after some time if the user disable the gps, will the LocationSettinsRequest onFailureCallback() gets called again ?? I think this is one time call back to check if gps is ON before requesting for location updates. What we can do if user turns OFF gps after some time ?? may be we should periodically check if gps is turned ON. – K Pradeep Kumar Reddy May 03 '20 at 13:50
1

After getting location just remove mFusedLocationClient.removeLocationUpdates as he mentioned in above answers.

if (mFusedLocationClient != null) 
        mFusedLocationClient.removeLocationUpdates(mLocationCallback);

Looper will be called requestLocationUpdates until you remove it.

In my problem, I did as I mention above. Below is my code.

  mFusedLocationClient.getLastLocation()
                    .addOnSuccessListener(new OnSuccessListener<Location>() {
                        @Override
                        public void onSuccess(Location location) {
                            // GPS location can be null if GPS is switched off
                            if (location != null) {

                                mLocation = location;

                                if (mFusedLocationClient != null) {
                                    mFusedLocationClient.removeLocationUpdates(mLocationCallback);
                                }
                          } else {
                                startLocationUpdates();
                           }
                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Toast.makeText(HomeActivity.this, "Error trying to get last GPS location", Toast.LENGTH_SHORT).show();
                            e.printStackTrace();
                        }
                    });

and below is my requestLocationUpdates so I will get a request until the location is available.

private void startLocationUpdates() {
        mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
                .addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
                    @Override
                    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
                        Log.i(TAG, "All location settings are satisfied.");

                        getPackageManager().checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, getPackageName());
                        mFusedLocationClient.requestLocationUpdates(mLocationRequest,
                                mLocationCallback, Looper.myLooper());
                        getLastLocationNewMethod();
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        int statusCode = ((ApiException) e).getStatusCode();
                        switch (statusCode) {
                            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                                Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade " +
                                        "location settings ");
                                try {
                                    ResolvableApiException rae = (ResolvableApiException) e;
                                    rae.startResolutionForResult(HomeActivity.this, 0x1);
                                } catch (IntentSender.SendIntentException sie) {
                                    Log.i(TAG, "PendingIntent unable to execute request.");
                                }
                                break;
                            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                                String errorMessage = "Location settings are inadequate, and cannot be " +
                                        "fixed here. Fix in Settings.";
                                Log.e(TAG, errorMessage);
                                Toast.makeText(HomeActivity.this, errorMessage, Toast.LENGTH_LONG).show();
                                //  mRequestingLocationUpdates = false;
                        }
                        getLastLocationNewMethod();  // this method is where I can get location. It is calling above method. 
                    }
                });
    }

Note: For more information here is GitHub Repo LINK

sushildlh
  • 8,986
  • 4
  • 33
  • 77
  • Can we call LocationSettingRequest from a foreground service ?? Because i'm requesting for location updates from a foreground serrvice – K Pradeep Kumar Reddy May 03 '20 at 13:41
  • According to what i understood, LocationSettingRequest check is done only once before requesting for location updates right ?? After starting request for location updates, after some time if the user disable the gps, will the LocationSettinsRequest onFailureCallback() gets called again ?? I think this is one time call back to check if gps is ON before requesting for location updates. What we can do if user turns OFF gps after some time ?? may be we should periodically check if gps is turned ON. – K Pradeep Kumar Reddy May 03 '20 at 13:51
  • Just use service for LocationSettingRequest. So it will check whenever you closed GPS ON or OFF. – sushildlh May 04 '20 at 06:24
  • We can not user LocationSettingsRequest from service to prompt the user with dialog, as this line needs activity context "rae.startResolutionForResult(HomeActivity.this, 0x1);" – K Pradeep Kumar Reddy May 05 '20 at 13:42
  • You must see this for service https://github.com/android/location-samples/blob/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice/LocationUpdatesService.java – sushildlh May 05 '20 at 14:58