Android : LocationManager vs Google Play Services
User Location on Android
Getting the user’s location on Android is a little less straightforward than on iOS. To start the confusion, there are two totally different ways you can do it. The first is using Android APIs from android.location.LocationListener
, and the second is using Google Play Services APIs com.google.android.gms.location.LocationListener
. Let’s go through both of them.
Android’s Location API
The Android’s location APIs use three different providers to get location -
LocationManager.GPS_PROVIDER
— This provider determines location using satellites. Depending on conditions, this provider may take a while to return a location fix.LocationManager.NETWORK_PROVIDER
— This provider determines location based on availability of cell tower and WiFi access points. Results are retrieved by means of a network lookup.LocationManager.PASSIVE_PROVIDER
— This provider will return locations generated by other providers. You passively receive location updates when other applications or services request them without actually requesting the locations yourself.
The gist of it is that you get an object of LocationManager
from the system, implement the LocationListener
, and call the requestLocationUpdates
on the LocationManager
.
Here’s a code snippet:
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
Google’s API Guide on Location Strategies explains the code pretty nicely. But they also mention that in most cases, you’ll get better battery performance, as well as more appropriate accuracy, by using the Google Location Services API instead. Now the confusion starts!
- Google’s Location Services API
Google’s Location Services API is a part of the Google Play Services APK (here’s how to set it up) . They’re built on top of Android’s API. These APIs provide a “Fused Location Provider” instead of the providers mentioned above. This provider automatically chooses what underlying provider to use, based on accuracy, battery usage, etc. It is fast because you get location from a system-wide service that keeps updating it. And you can use more advanced features such as geofencing.
To use the Google’s Location Services, your app needs to connect to the GooglePlayServicesClient
. To connect to the client, your activity (or fragment, or so) needs to implement GooglePlayServicesClient.ConnectionCallbacks
and GooglePlayServicesClient.OnConnectionFailedListener
interfaces.
Here’s a sample code:
public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
LocationClient locationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
locationClient = new LocationClient(this, this, this);
}
@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation() ;
Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show();
}
@Override
public void onDisconnected() {
Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// code to handle failed connection
// this code can be found here — http://developer.android.com/training/location/retrieve-current.html
}
- Why is
locationClient.getLastLocation()
null?
The locationClient.getLastLocation()
gets the last known location from the client. However, the Fused Location Provider will only maintain background location if at least one client is connected to it. Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and you call getLastLocation()
right away in onConnected()
, that might not be enough time for the first location to come in. This will result in location
being null
.
To solve this issue, you have to wait (indeterminately) till the provider gets the location and then call getLastLocation()
, which is impossible to know. Another (better) option is to implement the com.google.android.gms.location.LocationListener
interface to receive periodic location updates (and switch it off once you get the first update).
public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
// . . . . . . . . more stuff here
LocationRequest locationRequest;
LocationClient locationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// . . . . other initialization code
locationClient = new LocationClient(this, this, this);
locationRequest = new LocationRequest();
// Use high accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
locationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
locationRequest.setFastestInterval(FASTEST_INTERVAL);
}
// . . . . . . . . other methods
@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation();
if (location == null)
locationClient.requestLocationUpdates(locationRequest, this);
else
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
// . . . . . . . . other methods
@Override
public void onLocationChanged(Location location) {
locationClient.removeLocationUpdates(this);
// Use the location here!!!
}
In this code, you’re checking if the client already has the last location (in onConnected
). If not, you’re requesting for location updates, and switching off the requests (in onLocationChanged()
callback) as soon as you get an update.
Note that the locationClient.requestLocationUpdates(locationRequest, this);
has to be inside the onConnected
callback, or else you will get an IllegalStateException
because you will be trying to request for locations without connected to the Google Play Services Client.
- User has disabled Location Services
Many times, the user would have location services disabled (to save battery, or privacy reasons). In such a case, the code above will still request for location updates, but onLocationChanged
will never get called. You can stop the requests by checking if the user has disabled the location services.
If your app requires them to enable location services, you would want to show a message or a toast. Unfortunately, there is no way of checking if the user has disabled location services in Google’s Location Services API. For this, you will have to resort back to Android’s API.
In your onCreate
method:
LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationEnabled = false;
Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;
And use the locationEnabled
flag in your onConnected
method like this:
if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}
UPDATE
Document is updated, LocationClient is removed and the api supports to enable GPS with one click from dialog:
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
Link https://developer.android.com/training/location/change-location-settings#prompt
New location client: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
It is recommended to go through https://developer.android.com/training/location before doing any location tasks.
Android location vs Google Play Services
Answer from Dhruvam Gupta on the question Singh provided:
The Google Location Services API, part of Google Play Services, provides a more powerful, high-level framework that automatically handles location providers, user movement, and location accuracy. It also handles location update scheduling based on power consumption parameters you provide. In most cases, you’ll get better battery performance, as well as more appropriate accuracy, by using the Location Services API.
More detailed differences between the two apis Google Play Service Location API and Android Framework Location API can be found here
Are there any advantages of using FusedLocationProviderApi over LocationManager?
FusedLocationProvider uses a mix of hardware to determine location based on the context of the request, meaning it's optimized transparently to you. It will also cache captured locations between applications to avoid unnecessary work to determine location info. So if a user has a variety of location-aware apps, they potentially avoid taxing the device (and waiting) for a location capture as one may have already been cached.
While the ol' LocationManager will suffice in small, one-off situations, you should definitely consider the newer alternative as the benefits may be great, and the work to implement, easy.
You may as well use it as Google Play Services is regularly updated across devices, and continuously includes improvements to location-based features (and more).
A link to an explanation of the FusedLocationProvider at launch: https://www.youtube.com/watch?v=Bte_GHuxUGc
Getting location with the Google Play Services Location API vs getting it with the Awareness API
It really depends on your exact use case & requirements.
If you just need to know the location or want to receive locations updates regularly, go with the
LocationServices.FusedLocationApi
.If you have more complex, contextual requirements, for example you need to know when a user starts walking, or when a user enters an area, or something else that is based on the context of the user, you want to use the Awareness API.
To answer your question
However, is there any benefit in using (exclusively to obtain location) the Google Play Services Awareness API over the Google Play Services Location API?
No, none at all. The Awareness API was not created exclusively with the purpose of obtaining locations. LocationServices.FusedLocationApi
was however, so use that.
Related Topics
Sniffing/Logging Your Own Android Bluetooth Traffic
How to Get My Android Device Country Code Without Using Gps
How to Set Multiple Alarms Using Alarm Manager in Android
Disable the Notification Panel from Being Pulled Down
How to Make Notification Intent Resume Rather Than Making a New Intent
How to Determine the Screen Width in Terms of Dp or Dip at Runtime in Android
How to Customize Item Background and Item Text Color Inside Navigationview
Ionic Build Android | Error: No Installed Build Tools Found. Please Install the Android Build Tools
"Realm Migration Needed", Exception in Android While Retrieving Values from Realm Db
Stopping & Starting Music on Incoming Calls
Failed to Resolve Com.Android.Support:Appcompat-V7:22 and Com.Android.Support:Recyclerview-V7:21.1.2
Creating Custom Lockscreen in Android
How to Get Available Wifi Networks and Display Them in a List in Android
Android:Locationmanager VS Google Play Services
Android Onclick in Xml VS. Onclicklistener
How Do Mpandroidchart Renderers Work and How to Write a Custom Renderer