Perfect Geocoding Zoom: Part 2

Nov 6, 2011   //   by Theo   //   Blog  //  1 Comment

The Problem

Ever used the built-in Geocoder class in Android to display a location on a map? If so, you may have found that the geocoder does not provide you with the viewport data needed to zoom the map appropriately. Given the reality of different size locations (countries, states, cities, buildings) how can we zoom the map appropriately to show the complete location on the screen, at a zoom level that’s not too high and not too low?

The Solution

GeocoderPlus is a geocoding library that uses the Google Maps Web Services APIs V3 to retrieve both location coordinates and viewport info. Thanks to the viewport info, the GeocoderPlus library can display locations on a map at the right zoom level.

In Part 1 of this post we looked at the inner workings of the library. In this post we will build an sample app that shows a map and allows the user to enter a location. When the user presses Go, the app calls the GeocoderPlus library to retrieve matching addresses. If there are multiple addresses that match, the app asks the user to select the desired address. Finally, the app displays the selected address at the correct zoom on the map.

Installation

GeocoderPlus is provided as a JAR library. Download the library from here and add it to your Android project like any other JAR library.

Interface

The GeocoderPlus interface is similar to that of the Android geocoder. The exported Geocoder class contains these methods:

public List <Address> getFromLocationName(String locationName)
	throws IllegalArgumentException, IOException

public List <Address> getFromLocationName (String locationName, int maxResults)
	throws IllegalArgumentException, IOException

Usage

The following method shows how to perform geocoding and handle any exceptions:

public List<Address> geocodeLocation(String locationName)
{
	// Geocode the location
	Geocoder geocoder = new Geocoder();

	try
	{
		List<Address> addresses = geocoder.getFromLocationName(locationName);
		return addresses;
	}
	catch (IllegalArgumentException e)
	{
		e.printStackTrace();
	}
	catch (IOException e)
	{
		e.printStackTrace();
	}

	return null;
}

The geocoding call is a blocking call, so proper Android programming dictates that it should not take place on the UI thread. The easiest way to transfer the call to a different thread is to use the AsyncTask class. The code shown below extends the AsyncTask class and creates a new class called GeocodeTask. Within the new class, onPreExecute uses showLocationPendingDialog to display an indeterminate progress dialog with a status message. The doInBackground function is executed on a separate thread and calls our geocodeLocation() function (shown earlier) to perform the geocoding work. Once geocoding is complete, onPostExecute uses cancelLocationPendingDialog to hide the indeterminate progress dialog, and then takes appropriate action based on the number of results. The user will see a warning if there are zero results, a location picker if there are multiple results and the actual location if there is one result.

public class GeocodeTask extends AsyncTask<String, Void, List<Address>>
{
	// Removed helper function implementations for brevity. You can see
	// the full code in the Github repository

	@Override
	protected void onPreExecute()
	{
		super.onPreExecute();
		showLocationPendingDialog();
	}

	@Override
	protected List<Address> doInBackground(String... args)
	{
		// Declare
		List<Address> addresses;

		// Extract parameters
		String locationName = args[0];

		// Geocode
		addresses = geocodeLocation(locationName);

		// Return
		return addresses;
	}
	@Override
	protected void onPostExecute(List<Address> addresses)
	{
		super.onPostExecute(addresses);
		cancelLocationPendingDialog();

		// Check the number of results
		if (addresses != null)
		{
			if (addresses.size() > 1)
			{
				// Determine which address to display
				showLocationPicker(addresses);
			}
			else
			{
				// Display address
				displayLocation(addresses.get(0));
			}
		}
		else
		{
			showAlert("No results found!", "Error");
		}
	}
};

To display the address on the map, we use the data in the Address class (latitude, longitude, viewport latitude span, viewport longitude span) to center the map and set the zoom.

private void displayLocation(Address address)
{
	// Get the map center
	GeoPoint mapCenter = new GeoPoint((int) (address.getLatitudeE6()), (int) (address.getLongitudeE6()));

	// Get the map controller
	MapController mapController = mMapView.getController();

	// Fix position
	mapController.animateTo(mapCenter);

	// Fix zoom
	mapController.zoomToSpan(address.getViewPort().getLatitudeSpanE6(), address.getViewPort().getLongitudeSpanE6());
}

Finally, we can invoke the GeocodeTask class and perform geocoding in the background as follows:

String locationName = "Rome";
GeocodeTask geocodeTask = new GeocodeTask();
geocodeTask.execute(locationName);

Conclusion

This post showed how to use the GeocoderPlus library to display an address at the appropriate zoom level on a map.

The source code for this post is on Github at:
http://www.github.com/bricolsoftconsulting/GeocoderPlusExample/

One comment on “Perfect Geocoding Zoom: Part 2

  1. Shraddha Pawar on said:

    It has solved my problem of zoom but I am having another problem regarding poi search like
    poonam mall, etc. I get results while using Geocoder class but I am not getting results while using GeocoderPlus Library.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>