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.
1. 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 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);
}
|