14

I just updated my Location API to use FusedLocationProviderClient but I am having this issue, when I turn off and on the GPS, I am always getting null location:

val fusedLocationProviderClient =
                        LocationServices.getFusedLocationProviderClient(callingActivity)
            fusedLocationProviderClient.flushLocations()
            getLocationRequest()

            checkLocationSettings(callingActivity, turnOnGpsRequestCode, callback) {
                // Location settings successful
                fusedLocationProviderClient.lastLocation
                        .addOnSuccessListener(callingActivity) {
                            location ->
                            // Here location is always null
callback.onCallback(MenumyRadar.RadarStatus.SUCCESS, location)
                        }
                        .addOnFailureListener {
                            callback.onCallback(MenumyRadar.RadarStatus.ERROR_UNKNOWN, null)
                        }
            }

It doesn´t work until I open another app which uses location, as Google Maps or Uber.

I have some clue thanks to this answer FusedLocationApi.getLastLocation always null

And to Google´s explanation:

fusedLocationClient.lastLocation .addOnSuccessListener { location : Location? -> // Got last known location. In some rare situations this can be null. }

The getLastLocation() method returns a Task that you can use to get a Location object with the latitude and longitude coordinates of a geographic location. The location object may be null in the following situations:

Location is turned off in the device settings. The result could be null even if the last location was previously retrieved because disabling location also clears the cache. The device never recorded its location, which could be the case of a new device or a device that has been restored to factory settings. Google Play services on the device has restarted, and there is no active Fused Location Provider client that has requested location after the services restarted. To avoid this situation you can create a new client and request location updates yourself. For more information, see Receiving Location Updates.

But it does not say how to handle this, what can I do?

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • it returns null because it takes time to get the last known location. so what you can do is, check if the location is null or not, if yes then show toast – Ankur_009 Apr 26 '18 at 16:32
  • Even if I wait for 10-15 minutes, it keeps returning null until I open Google Maps – Jesus Almaral - Hackaprende Apr 26 '18 at 16:38
  • 1
    It sounds like you're clearing the location cache by turning "off the GPS" and then asking for the LAST location and getting null. That seems like expected behavior to me. If you need to get a location fix, check LAST first and if it's null then you need to add a LocationRequest and listen. That will take a bit to get a fix, if it can, and fire the callback and THEN you will have both your location and a LAST location for next time. – Charlie Collins Apr 26 '18 at 17:52
  • @Ankur_009 did you find a solution yet? – Json May 20 '18 at 12:05
  • Have you tried moving the phone around? AFAIK it only updates the cache when the position changes. – DrMcCleod Jul 06 '18 at 12:16
  • See an [article](https://droidbyme.medium.com/get-current-location-using-fusedlocationproviderclient-in-android-cb7ebf5ab88e), it overcomes some bugs, but doesn't work on old emulators. – CoolMind Jan 19 '21 at 15:07

2 Answers2

13

I found a solution, this is what happens, when the location is null it means the location cache was cleared, this happens when turning off GPS, so when I was turning it on there was no last location to get, what I did was this:

checkLocationSettings(callingActivity, turnOnGpsRequestCode, callback) {
                // Location settings successful
                mFusedLocationProviderClient!!.lastLocation
                        .addOnSuccessListener(callingActivity) {
                            location ->
                            if (location == null || location.accuracy > 100) {
                                mLocationCallback = object : LocationCallback() {
                                    override fun onLocationResult(locationResult: LocationResult?) {
                                        stopLocationUpdates()
                                        if (locationResult != null && locationResult.locations.isNotEmpty()) {
                                            val newLocation = locationResult.locations[0]
                                            callback.onCallback(Status.SUCCESS, newLocation)
                                        } else {
                                            callback.onCallback(Status.ERROR_LOCATION, null)
                                        }
                                    }
                                }

                                mFusedLocationProviderClient!!.requestLocationUpdates(getLocationRequest(),
                                        mLocationCallback, null)
                            } else {
                                callback.onCallback(Status.SUCCESS, location)
                            }
                        }
                        .addOnFailureListener {
                            callback.onCallback(Status.ERROR_UNKNOWN, null)
                        }
            }

When the location is null, start requesting locations using a callback and

mFusedLocationProviderClient!!.requestLocationUpdates(getLocationRequest(), mLocationCallback, null)

Then when the callback is called, a new location is got and it starts getting location again.

Sometimes it happens that when you turn on the GPS, the location is not null but the accuracy is bad, so I also check if location accuracy is good enough (For me good enough is 100 meters)

1

You can use getLocationAvailability() method on your FusedLocationPrivedClient object and if it returns true then only use getLastLocation() method otherwise use requestLocationUpdates() method like this :

FusedLocationProviderClient fusedLocationProviderClient =
            LocationServices.getFusedLocationProviderClient(InitActivity.this);
    if (ActivityCompat.checkSelfPermission(this.getApplicationContext(),
            android.Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {

fusedLocationProviderClient.getLocationAvailability().addOnSuccessListener(new OnSuccessListener<LocationAvailability>() {
                @Override
                public void onSuccess(LocationAvailability locationAvailability) {
                    Log.d(TAG, "onSuccess: locationAvailability.isLocationAvailable " + locationAvailability.isLocationAvailable());
                    if (locationAvailability.isLocationAvailable()) {
                        if (ActivityCompat.checkSelfPermission(InitActivity.this.getApplicationContext(),
                                android.Manifest.permission.ACCESS_FINE_LOCATION)
                                == PackageManager.PERMISSION_GRANTED) {
                            Task<Location> locationTask = fusedLocationProviderClient.getLastLocation();
                            locationTask.addOnCompleteListener(new OnCompleteListener<Location>() {
                                @Override
                                public void onComplete(@NonNull Task<Location> task) {
                                    Location location = task.getResult();                                    
                                }
                            });
                        } else {
                            requestLocationPermissions ();
                        }

                    } else {
fusedLocationProviderClient.requestLocationUpdates(locationRequest, pendingIntent);

                    }

                }
            });
        } else {
            requestLocationPermissions ();
        }
Ssubrat Rrudra
  • 870
  • 8
  • 20
  • 1
    What is `pendingIntent`? `locationAvailability?.isLocationAvailable == false` in fresh API 19 emulator. – CoolMind Jan 19 '21 at 14:14