Reputation: 3652
I want my Kotlin app to get the current accurate (GPS) location once only when requested by the user.
Up to now I've been using fusedLocationClient.lastLocation
. This has generally worked successfully, but occasionally the app returns a distant location (sometimes a mile or two away) even when Google Maps and another app running on the same phone have an accurate GPS location.
I've tried implementing the getCurrentLocation method using code from How to get location using "fusedLocationClient.getCurrentLocation" method in Kotlin?. However, Android Studio reports an error at fusedLocationClient.getCurrentLocation(PRIORITY_HIGH_ACCURACY, object : CancellationToken()
saying that I should either:
"Rename reference"
or
"Create extension function for 'FusedLocationProviderClient.getCurrentLocation'"
Is it possible to force the lastLocation
method to use the GPS location? (In the Manifest I have only included the ACCESS_FINE_LOCATION
permission, but that doesn't seem to do the job.)
Failing that, can anyone show me how to create an extension function for the getCurrentLocation
method, please?. I've not found any examples online.
EDIT, following Gabe Sechan's answer
Although the FusedLocation provided by Google Play Services is often said to be what Google prefers, it cannot be relied on to provide the most accurate available location, as Gabe Sechan has commented in his answer.
For my purpose, therefore, I have turned to imthegaga's code provided in his answer in Android Location Manager, Get GPS location ,if no GPS then get to Network Provider location - Stack Overflow. This code uses the Android location classes to get the last known locations from the GPS Provider if available and from the Network Provider if available and, if both are available, returns the more accurate one.
Upvotes: 0
Views: 2872
Reputation: 395
After spending a couple of hours, I was able to fix my current location issue. I have separated the code in a separate class. You can use following class to get current location.
public class LocationTracker {
public static void getCurrentLocation(
@NonNull Context context,
OnLocationChangeListener onLocationChangeListener
) {
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
AtomicBoolean foundLocation = new AtomicBoolean(false);
Consumer<Location> locationConsumer = location -> {
if (!foundLocation.get()) {
foundLocation.set(true);
if (location != null) {
onLocationChangeListener.onComplete(getLatLng(location));
} else {
onLocationChangeListener.onComplete(new LatLng(0.0, 0.0));
}
}
};
registerLocationCallbackListener(locationManager, LocationManager.GPS_PROVIDER, locationConsumer);
registerLocationCallbackListener(locationManager, LocationManager.NETWORK_PROVIDER, locationConsumer);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
registerLocationCallbackListener(locationManager, LocationManager.FUSED_PROVIDER, locationConsumer);
}
}
private static void registerLocationCallbackListener(
LocationManager locationManager, String networkProvider, Consumer<Location> locationConsumer
) {
LocationManagerCompat.getCurrentLocation(locationManager, networkProvider,
new CancellationSignal(), Executors.newSingleThreadExecutor(), locationConsumer
);
}
@NonNull
private static LatLng getLatLng(@NonNull Location location) {
return new LatLng(location.getLatitude(), location.getLongitude());
}
public interface OnLocationChangeListener {
void onComplete(LatLng latLng);
}
}
Usage
LocationTracker.getCurrentLocation(context, new OnLocationChangeListener() {
@Override
public void onComplete(LatLng latLng) {
}
}
);
Upvotes: 1
Reputation: 93708
Ok, a few confued concepts here.
1)Fused location is NOT GPS. It can be, but it may not be. Fused is an attempt to combine GPS (high power drain, slow lock) with Network (low power drain, requires server assistance) to provide a blend of accuracy and power. If you want GPS, you need to use the Android location classes, not the Google Play FusedLocation stuff (bonus is the Android stuff works even if you don't have Google Play on the device).
2)lastLocation returns a cached location. It doesn't update the location, or get the current location. It returns the location of the last time the location functionality was turned on. Which could be very old, or could be null if there is no cached data. It's an optimization, and should only be used if you know what you're doing and don't need up to date data. If you do, you need to use requestLocationUpdates which actually turns on the location subsystem and finds the location.
Upvotes: 2