For managing location based information, Android provides the android.location package which in turn gives us the LocationManager class that gives us access to location based functions such as the latitude and longitude of a device's position. Tracking a device over time is made equally convenient and the LocationListener class monitors changes in location as they occur.
Listening for location changes is only a part of the story, as Google provides APIs for managing Google Maps data and displaying and manipulating maps through the use of the MapView and MapController classes. These powerful tools require us to sign up with Google first, and once done enable us to zoom in and out of maps, pan to any location that we are looking for, and when we want to, include application information on a map, and even add our own layers to maps and mark locations on a Google map.
Android locations are expressed in terms of latitude and longitude coordinates. The default format is degrees. The Location object can also be used to store a time-stamp and other information such as speed and distance traveled.
Although obtaining a device's last known location does not always yield the most accurate information, it is often the first reading that we may want. It is fast, simple to employ, and makes a good introduction to the LocationManager.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
android:id="@+id/text_view"
TextView textView;
textView = (TextView) findViewById(R.id.text_view);
LocationManager manager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
Location loc =
manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
textView.setText("latitude: " + loc.getLatitude()
+ "nlongitude: " + loc.getLongitude());
The use of a LocationManager to obtain the device's last known location is very straightforward. As with other system services, we obtained it with getSystemService() and the getLastKnownLocation() method returns the Location object itself, which can be further queried to provide latitude and longitude coordinates. We could have done more with the Location object, for example Location.getAltitude() will return altitude and getDistance(Location) and getBearing(Location) will return distance and bearing to another Location.
It is possible to send mock locations to an emulator using the DDMS perspective in Eclipse:
Before sending location data this way, make sure that you have set the emulator to allow mock locations under Settings | Applications | Development.
It is worth noting that although use of the getLastKnownLocation() method may not always be accurate, particularly if the device has been switched off for some time, it does have the advantage of yielding almost immediate results.
Using GPS to obtain a location has a couple of drawbacks. Firstly, it does not work indoors; and secondly, it is very demanding on the battery. Location can be determined by comparing cell tower signal strengths, and although this method is not as accurate, it works well indoors and is much more considerate to the device's battery.
The network provider is set up in exactly the same way as the previous GPS example, simply exchange the Location declaration with:
Location loc =
manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
You will also need to change, or amend, the permission in the manifest file with:
<uses-permission
android_name="android.permission.ACCESS_COURSE_LOCATION" />
Obtaining the last known location as we did in the previous recipe is all well and good and handy for retrieving a Location quickly, but it can be unreliable if the handset has been switched off or if the user is on the move. Ideally we want to be able to detect location changes as they happen and to do this we employ a LocationListener.
In this recipe we will create a simple application that keeps track of a mobile device's movements.
This task can be performed most easily by starting where the previous one left off. If you have not completed that task yet, do so now—it is very short—then return here. If you have already completed the recipe then simply open it up to proceed.
LocationManager manager;
LocationListener listener = new MyLocationListener();
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
30000, 50, listener);
Location location =
manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
LocationListener: public class MyLocationListener implements LocationListener { }
@Override
public void onLocationChanged(Location l) {
textView.setText("/n/nlatitude: " +
l.getLatitude() + "nlongitude: " + l.getLongitude());
}
@Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
protected void onResume() {
super.onResume();
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
30000, 50, listener);
}
@Override
protected void onPause() {
super.onPause();
manager.removeUpdates(this);
}
In this recipe we used the LocationManager to provide location updates roughly every 30 seconds (30000 milliseconds) or whenever the location changed by more than 50 meters. We say 'roughly' because these values work only as a guide and the actual frequency of updates often varies from the values we set. Nevertheless, setting these two parameters of the requestLocationUpdates() method to high values can make a big difference to the amount of battery power the GPS provider consumes. Hopefully the use of the provider and the LocationListener as the other two parameters is self explanatory.
The LocationListener operates very much as other listeners do and the purpose of the onProviderEnabled() and onProviderDisabled() should be clear. The onStatusChanged() method is called whenever a provider becomes unavailable after a period of availability or vice versa. The int, status can represent 0 = OUT_OF_SERVICE, 1 = TEMPORARILY_UNAVAILABLE, or 2 = AVAILABLE.