Geocoding tutorial – Accessing Google Static Maps from Java
Posted April 21st, 2008 by NazmulComprehensive Real-World BlackBerry Training Courses by developerlife.com
Want to learn from the Masters? We’ve created groundbreaking BlackBerry software (we are finalists in the 2009 BlackBerry Developer Challenge). We have a complete set of instructor-led training courses available for BlackBerry development that will turbo-charge your BlackBerry development efforts. Whether you are a newbie or an experienced developer, we have modules that will fit your needs. Learn more about our courses & schedule.
Introduction
Google just released a new API that allows access to ’static’ maps. Static maps are GIF images that are generated based on a longitude/latitude that’s passed to the Google Static Map API. In this tutorial, you will see how to use this API from Java applications. I’ve created a Java adapter to the API that will allow you to quickly access all the Static Map API features. I’ve also provide a graphical application that you can use as a test harness to the see the API in action.
You need a latitude and longitude in order to start using the API. You can get this lat/lon pair from a GeoIP database (as shown here and here), or a GPS receiver, or just type it in manually.
Also, the ‘normal’ Google Maps API is geared for use in JavaScript, and the Static API doesn’t involve any JavaScript.
License key
You will need to sign up for a license key in order to use this API. You can learn more about it here. You can sign up for a key here. A license key will allow 1000 accesses in a 24 hour period. I’ve designed the Java API to access the Static Maps API in a way that you can easily cache maps that the Static Maps API generates.
Background Information
To learn more about geocoding and the Google Maps API, read this chapter in the Google Maps Hack book (on Safari Books Online). Locations on earth can be specified by a combination of longitude, latitude, and elevation. You can read all about it here on wikipedia. The following code is enough to identify a geographic location:
double latitude; double longitude;
This is the bare minimum information that you will need, but you will be able to get by and interface with many location based services just with this data. How do you get this long/lat data? If your app has access to a GPS device, then it can read the GPS coordinates from it (NMEA standard) – the GPS receiver sends lat/long information every few seconds via a serial port, USB, or Bluetooth connection to your laptop or mobile device, and you can then use that data. Alternatively, if you know the IP address where your desktop, mobile, or web based app is running, then you might be able to get geographic information out of it. There are issues with this and it’s not always reliable, and these issues are explained here.
Source code
You can download the source code to access the Java adapter for the Google Static Maps API service here.
The main class that you have to deal with in order to use the API is MapLookup, which is a static class located in the Provider.GoogleMapsStatic package. The class is very easy to use, but it must be initialized with a license key, otherwise, you will get errors returned when you try and get a map image from Google.
Usage example
The following code is the main() method implementation of the MapLookup class, and you can run it to get a feel for how to use the API:
public static void main(String[] args) { // make sure to set a valid license key setLicenseKey(""); double lat = 38.931099; double lon = -77.3489; double lat1 = 40.742100; double lon1 = -74.001801; String u1 = getMap(lat, lon); System.out.println(u1); String u2 = getMap(lat, lon, 256, 256); System.out.println(u2); String u3 = getMap(lat, lon, new MapMarker(lat, lon, MapMarker.MarkerColor.blue, 'a')); System.out.println(u3); String u4 = getMap(lat, lon, 250, 500, new MapMarker(lat, lon, MapMarker.MarkerColor.green, 'v'), new MapMarker(lat1, lon1, MapMarker.MarkerColor.red, 'n') ); System.out.println(u4); }
There are many different ways to use the API as you can see from this code. The methods getMap(…) return a String URI that can be resolved to get the map image from Google. All the parameters that you give the MapLookup class are used to generate this URI that is compliant with what Google expects. The MapLookup class also performs range validation checking for input parameters. The following is a list of methods you can call:
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // set the license key //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX public static void setLicenseKey(String lic) { GmapLicense = lic; } //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // methods //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX public static String getMap(double lat, double lon) { return getMap(lat, lon, SizeMax, SizeMax); } public static String getMap(double lat, double lon, int sizeW, int sizeH) { return getMap(lat, lon, sizeW, sizeH, ZoomDefault); } public static String getMap(double lat, double lon, int sizeW, int sizeH, int zoom) { return _map.getURI(lat, lon, sizeW, sizeH, zoom); } public static String getMap(double lat, double lon, int sizeW, int sizeH, MapMarker... markers) { return _map.getURI(lat, lon, sizeW, sizeH, markers); } public static String getMap(double lat, double lon, MapMarker... markers) { return getMap(lat, lon, SizeMax, SizeMax, markers); }
All the getMap(…) methods return a String URI that can be resolved to get a map image from Google. Most of the methods are pretty straightforward. The class validates your input params to make sure that they are in range. Here’s a list of restrictions:
- size width and height – max of 512 pixels
- zoom – zoom level between 0 and 19.
Make sure to call setLicenseKey() to set the license key supplied to you by Google, when you sign up.
To turn the URI into a GIF use the getDataFromURI(String) method:
/** use httpclient to get the data */ public static ByteBuffer getDataFromURI(String uri) throws IOException { GetMethod get = new GetMethod(uri); try { new HttpClient().executeMethod(get); return new ByteBuffer(get.getResponseBodyAsStream()); } finally { get.releaseConnection(); } }
Graphical test harness
A full blown graphical test harness is provided so that you can get familiar with the API. Here’s a screenshot of this app in action:
To run the harness, run the SampleApp class in the Provider.GoogleMapsStatic.TestUI package. If you have IDEA, then a GeoIPLookup.ipr project file is provided with a run configuration for this graphical test harness. Make sure that you have a license key pasted into the License Key field, otherwise you will get an error.
Using the harness
The graphical app can be used to access simple API functions. You have to provide a width and height for the map size that you’re expecting. The max size is 512 pixels for each. Also you have to provide a latitude and longitude, these are just Java double values. When you click on "Get Map", the app generates a URI, which is then resolved into a GIF image that’s displayed. The Task API is used to load this map in the background. For more information on the Task API, start here.
Advanced API usage
Simple usage of the API is covered by the test harness. Advanced usage constitutes using "markers". My API makes it really easy to work with markers! There’s a getMap(…) variant that takes any number of MapMarker objects. These objects represent "pushpins" that you want to show up on the map itself. You can pass any number of these to the API. Here’s the MapMarker class:
/** * {latitude} (required) specifies a latitudinal value with precision to 6 decimal places. * {longitude} (required) specifies a longitudinal value with precision to 6 decimal places. * {color} (optional) specifies a color from the set {red,blue,green}. * {alpha-character} (optional) specifies a single lowercase alphabetic character from the set {a-z}. * <p/> * An example marker declaration is of the form {latitude},{longitude},{color}{alpha-character}. Note * in particular that the color and alpha-character values of the string are not separated by a comma. * A sample marker declaration is shown below. * <p/> * markers=40.702147,-74.015794,blues|40.711614,-74.012318,greeng&key=MAPS_API_KEY */ public class MapMarker implements Serializable { static final long serialVersionUID = 5805831996822361347L; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // enum for marker colors //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX enum MarkerColor { red, green, blue }// enum MarkerColor //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // data //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX private char _alpha = '1'; private MarkerColor _color = null; private double _lat = -1; private double _lon = -1; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // constructor //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX public MapMarker(double lat, double lon, MarkerColor color, char alpha) { _lat = lat; _lon = lon; _color = color; _alpha = alpha; StringBuffer buf = new StringBuffer(); buf.append(alpha); if (!Pattern.matches("[a-zA-Z]", buf)) throw new IllegalArgumentException("marker alpha is not a char between a-z"); if (color == null) throw new IllegalArgumentException("marker color can not be null"); } public MapMarker(double lat, double lon) { _lat = lat; _lon = lon; } //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // generate Google Maps uri //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX public String toString() { StringBuilder sb = new StringBuilder(); sb.append(_lat).append(",").append(_lon); if (_color != null && _alpha != '1') { sb. append(","). append(_color.toString()). append(_alpha); } return sb.toString(); } }// class Marker
You can create a MapMarker just by providing a lat/lon pair. You can also provide a color and alphabet designation along with the lat/lon. The API takes care of translating this into URL parameters that the Google Static Maps API will understand. Here’s are some examples:
String u3 = getMap(lat, lon, new MapMarker(lat, lon, MapMarker.MarkerColor.blue, 'a')); System.out.println(u3); String u4 = getMap(lat, lon, 250, 500, new MapMarker(lat, lon, MapMarker.MarkerColor.green, 'v'), new MapMarker(lat1, lon1, MapMarker.MarkerColor.red, 'n') ); System.out.println(u4);
In the code above (part of the main()), you can see how to create MapMarker objects really easily!
Example of integrating this into an app
When you put the Static Maps API together with the GeoIP APIs, then you can create some really useful and compelling functionality in your applications – be they mobile, web, or desktop based. In the ScreamingToaster Platform, I’ve created functionality that embeds geocode information into every aspect of the user experience. Here’s an example of this in action:
Comments and feedback
To share your thoughts on this tutorial, click here.
Training Services
Want to learn from the best in the business? We have training programs available for BlackBerry development, Android development, rich desktop apps, and UX design. We can give your development team a competitive edge, and make them experts in these technologies. Contact us if you are interesting in learning more about our training services & schedule.
Consulting Services
If you need help building web, mobile, and desktop apps that are all connected to the cloud, we can help. We can empower your business by bringing your ideas to life. Contact us if you have a project you need our help with and we will consider taking you on as a client.
Our expertise: architecture, UX design, graphic design, and implementation services for BlackBerry, Android, GWT, desktop Java, and cloud computing. Our specialties: crafting stunning UXes, LBS, real-time collaboration and syncing between services and web/mobile/desktop apps, location based mobile e-commerce, and location based mobile advertising.