Getting user’s current location using GPS (or network…)

One of the major features of Dublin Buzz – and what makes it a mobile application – is its knowledge about the user’s whereabouts. This is obtained by using the built-in GPS location chip on the Android device, if it has one. Alternatively, if the user has GPS switched off for any reason, or they prefer not to use it to conserve battery, the less accurate network location provider can be used. This posting will show you the steps to obtain location data.

loc = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

This first line of code obtains the LocationManager object. This will be the service API that provides us with all of the location finding services we will be needing. The loc object is defined as:

	public LocationManager loc = null;

All the code for loading a specific provider (either GPS or network) is done in DublinBuzz.java. That code is in a Word document available here: DublinBuzz.

The relevant code for getting a provider of location data is here:

/**
* Sets up the providing of location information for the user
*/
private void setupLocationProvider() {
    provider = app.loc.getBestProvider(getLocationProviderCriteria(), true);
    if (provider==null)
    {
    	Button b = (Button)findViewById(R.id.DistanceButton);
    	b.setTextColor(Color.DKGRAY);
    	b.setEnabled(false);
    }
    else
    {
    	currentLocation = app.loc.getLastKnownLocation(provider);
    	if (currentLocation != null)
    	{
    	    for (Sight s : app.sights)
   		s.refreshDistanceFromCurrentLocation(currentLocation);
    	}
    }
  // We have a location provider, so now create and add a listener for updating
  // periodically. We can then refresh distance too.
  updater = new LocationListener() {
  public void onLocationChanged (Location location){
  	currentLocation = location ; 
  	for (Sight s : app.sights)
  		s.refreshDistanceFromCurrentLocation(location);
  		if (app.preferredButton==R.id.DistanceButton)
  			ShowDistance(null);
  		else
  			displaySights(null);
  }
  public void onProviderDisabled(String provider)
  { 	}
  public void onProviderEnabled(String provider)
  {	}
  public void onStatusChanged(String provider, int status, Bundle extras){}
  };
  if (provider !=null)
  {
  	app.loc.requestLocationUpdates(provider, timeBetweenUpdates, distanceBeforeUpdates, updater);
  }
}

The very first line (provider = app.loc.getBestProvider(getLocationProviderCriteria(), true);) asks the LocationManager to find out what the best provider would be, given the set of criteria returned from the getLocationProviderCriteria() method call. I’ll explain a little about those criteria later on in the post, but for now, rest assured that those criteria specify things like cost, accuracy, and capability of the provider. If no provider is available, then the application cannot display distance data! So it reverts to turning off the “By Distance” button. Obviously, this is not ideal behaviour. But the philosophy of Android is to allow the end-user (who is boss) to decide whether to use GPS or not. After all of the controversy over iPhones and Androids storing location data, this is a power that users should have.

I then try and get the last available/known location data for the user. Then I update the distance data for every individual sight in turn:

currentLocation = app.loc.getLastKnownLocation(provider);
if (currentLocation != null)
{
    for (Sight s : app.sights)
	s.refreshDistanceFromCurrentLocation(currentLocation);
}

The following code creates a listener for location updates. Obviously, location changes as the user moves about. One of its key aspects is its very dynamism. This means that callbacks have to be defined to handle the changing location data. This is fully customisable by the programmer. In our case, we define an onLocationChanged method that does two main things: it updates the distance data for all sights; and it redisplays the list of sights if the user is currently looking at them ordered by distance:

// We have a location provider, so now create and add a listener for updating
// periodically. We can then refresh distance too.
updater = new LocationListener() {
public void onLocationChanged (Location location){
	currentLocation = location ; 
	for (Sight s : app.sights)
	    s.refreshDistanceFromCurrentLocation(location);
    	    if (app.preferredButton==R.id.DistanceButton)
    	        ShowDistance(null);
    	    else
    		displaySights(null);
    	    }

Finally, the location manager must be told where and how often to send location updates to:

   app.loc.requestLocationUpdates(provider, timeBetweenUpdates, 
   	distanceBeforeUpdates, updater);

The requestLocationUpdates method does what it says. It takes four arguments: the type or provider we want to ask for updates from (obtained earlier), the time in milliseconds between each update, the distance between updates, in meters, and the listener which will process those updates. The time and distance arguments need to be set just low enough to provide frequent and accurate updates, but not too low, as that would be a battery wasting hog. In my Dublin Buzz application, I have set these arguments to 10,000 ms and 10 meters respectively:

private static final long timeBetweenUpdates = 10000; // milliseconds between updates
private static final float distanceBeforeUpdates = 10; // meters moved before needing updates

The application can now display accurate, dynamic distance information for the user. I’ll explain more about that in a further post, but for now, enjoy the view!. As you can see below, you can tell that I actually live in Dublin. I live in Kilmainham, actually, so the data seems to be accurate enough.

Advertisements
This entry was posted in Android, Android development, Mobile Apps. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s