Sorry about the red box, but we really need you to update your browser. Read this excellent article if you're wondering why we are no longer supporting this browser version. Go to Browse Happy for browser suggestions and how to update.

Geocoding and reverse geocoding

You can use the net.rim.device.api.lbs.maps.server package to retrieve geographic coordinates for a location (geocoding) or a human-readable name for a location (reverse geocoding).

Geocoding and reverse geocoding requests can be either synchronous or asynchronous. To create an asynchronous call, your app must implement the ServerExchangeCallback interface.

When a successful request occurs, a ReverseGeocodeExchange object or a GeocodeExchange object is returned to your app. These objects contain a Vector of MapLocation objects that contain details about the locations that you specified in your requests.

Retrieving geographic coordinates for an address by using geocoding

Your app can use the Geocoder class to retrieve the geographic coordinates for an address. For example, your app can prompt the user for an address and then display the address on a map. The address can be in the form of an unstructured string, or a MapLocation object. Geocoding requests can be synchronous or asynchronous.

Specifying an address

The more details that you provide for an address, the more accurate the results can be. For example, if you provide only a street address, the Geocoding server might return a large number of results. However, if you provide sufficient geographic context with your request, you can get away with providing less information about the address. The unstructured address string doesn't always provide the same results as a structured address.

//Structured address

MapLocation address1 = new MapLocation();
address1.addData(MapLocation.LBS_LOCATION_CITY_KEY, "waterloo");
address1.addData(MapLocation.LBS_LOCATION_COUNTRY_KEY, "canada");
address1.addData(MapLocation.LBS_LOCATION_STREET_ADDRESS_KEY, "419 phillip st");
address1.addData(MapLocation.LBS_LOCATION_POSTAL_CODE_KEY, "N2L3X2");

//Unstructured address
 
String address2 = new String("419 phillip st, waterloo, canada, N2L3X2");

Providing geographic context with the address

To help the geocoding server return the most relevant results, provide geographic context with your geocoding request. To provide context, you can create a MapDimensions object that contains geographic coordinates (for example, the BlackBerry device user's current location). By providing context, your app can receive relevant geographic coordinates even if a user provides only an address. If you don't provide a MapDimensions object, your app might use the last location saved in BlackBerry Maps as context, which might not provide the results that you want.

As a best practice, you should provide context from your app. If your app doesn't provide sufficient context with a request, your app might receive irrelevant search results. When you create a MapDimensions object to use with geocoding requests, the values for the width, height, zoom, and rotation are not important.

MapPoint origin = new MapPoint(43.4815, -80.5407);

MapDimensions context = new MapDimensions(origin, 480, 360, 5, 0);

Sending an asynchronous geocoding request

When you send an asynchronous geocoding request, you must pass in a reference to the class that implements the ServerExchangeCallback interface (represented by the callback variable in the following code sample). You must also provide the address, geographic context for the request (for example, the user's current location), and the length of time before the request times out. When you invoke Geocoder.geocode(), the app sends the request to the geocoding server and calls the appropriate ServerExchangeCallback method when it has a result.

MyServerExchangeCallback callback = new MyServerExchangeCallback();

try
{
    Geocoder.getInstance().geocode(callback, address1, context, 0);
} 
catch (GeocodeException e)
{
    // Do something with the exception.
}

To create a class that implements the ServerExchangeCallback interface, there are three methods that you must include in your app: requestSuccess(), requestFailure(), and requestHalted(). When a geocoding request is completed, your app invokes one of these methods depending on the result of the request.

A successful geocoding request returns a GeocodeExchange object which contains a Vector of search results that you can access by invoking GeocodeExchange.getResults(). Each index in the Vector contains a net.rim.device.api.lbs.maps.model.MapLocation object that has details about a location, such as a display name, a description, the coordinates, and the address. If you receive multiple results, the most relevant result is located in the first index of the Vector.

public class MyServerExchangeCallback implements ServerExchangeCallback
{
    public void requestSuccess(ServerExchange exchange)
    {
        if(exchange instanceof GeocodeExchange)
        {
            GeocodeExchange geocodeExchange = (GeocodeExchange)exchange;
            Vector results = geocodeExchange.getResults();

            // Do something with the results
        }
    }

    public void requestFailure(ServerExchange exchange)
    {
        // Inform the user of the failure
    }

    public void requestHalted()
    {
        // Invoked when the request is stopped
    }
}

Sending a synchronous reverse geocoding request

For synchronous geocoding requests, your app is not required to implement the ServerExchangeCallback interface. To initiate a synchronous geocoding request, you must specify null instead of passing in a reference to a class that implements ServerExchangeCallback. When you run a synchronous geocoding request, you must verify the result of the request manually. Typically, you should run synchronous geocoding requests on a thread other than the UI thread; otherwise users won't be able to interact with the UI during the request.

GeocodeExchange exchange = Geocoder.getInstance().geocode
        (null, address2, context, 0);
                    
//Check if the request was successful
if(exchange.getExceptionList().size() == 0)
{
//Do something with the result of the request
}
else
{
//Inform the user of the failure
}

Code sample: Retrieving geographic coordinates for an address by using geocoding

The following code sample demonstrates how to retrieve the geographic coordinates for an address by using an asynchronous geocoding request. Even though the request specifies only a street address, the geocoding server is able to return a relevant set of coordinates because of the geographic context that is included with the request. When the app receives the results of the search, it displays the latitude and longitude on the screen.

import net.rim.device.api.lbs.maps.MapDimensions;
import net.rim.device.api.lbs.maps.model.*;
import net.rim.device.api.lbs.maps.server.*;
import net.rim.device.api.lbs.maps.server.exchange.*;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.MainScreen;
import java.util.Vector;

public class GeocodingDemo extends UiApplication
{
    public static void main(String[] args)
    {
        GeocodingDemo app = new GeocodingDemo();
        app.enterEventDispatcher();
    }
      
    public GeocodingDemo()
    {
        pushScreen(new GeocodingDemoScreen());
    }
      
    public class GeocodingDemoScreen extends MainScreen
    {
        private LabelField _resultsField;
        
        public GeocodingDemoScreen()
        {
            setTitle("Geocoding Demo");
            
            _resultsField = new LabelField();
            add(_resultsField);
            
            // Geographic context that is sent with the request.
            MapDimensions location = new MapDimensions(
                    new MapPoint(43.4815, -80.5407), 480, 360, 5, 0);           
            
            // The address used in the request. Only the street name is 
            // required, since geographic context is provided that
            // indicates the search is coming from Waterloo, Ontario.
            MapLocation address = new MapLocation();
            address.addData(MapLocation.LBS_LOCATION_STREET_ADDRESS_KEY, 
                    "419 phillip st");
            
            // Create an instance of the class that implements 
            // ServerExchangeCallback.
            MyServerExchangeCallback callback = new MyServerExchangeCallback();
            
            try
            {
                // Initiate the reverse geocoding request.
                Geocoder.getInstance().geocode(callback, address, location, 0);
            } 
            catch (GeocodeException e)
            {
                // Do something with the exception.
            }   
        }
        
        public class MyServerExchangeCallback implements ServerExchangeCallback
        {
            // StringBuffer used to display the location information from the request.
            StringBuffer buffer = new StringBuffer();
        
            public void requestSuccess(ServerExchange exchange)
            {
                if(exchange instanceof GeocodeExchange)
                {
                    // Cast the Exchange object to a GeocodeExchange object
                    // and retrieve the Vector of results.
                    GeocodeExchange geocodeExchange = (GeocodeExchange)exchange;
                    Vector results = geocodeExchange.getResults();
                    
                    // Iterate through each MapLocation object in the Vector 
                    // (can be many results depending on the context you provide 
                    // with the request).
                    for(int i = 0; i < results.size(); i++)
                    {
                        // Retrieve the lat and lon from the MapLocation object 
                        // and appends it to the StringBuffer.
                        MapLocation location = (MapLocation) results.elementAt(i);
                        buffer.append("Latitude: ").append(location.getLat())
                                .append('\n');
                        buffer.append("Longitude: ").append(location.getLon())
                                .append('\n');
                    }

                    // Take control of the UI thread and displays the location 
                    // information on the screen.
                    synchronized(UiApplication.getEventLock())
                    {
                        _resultsField.setText(buffer.toString());
                    }
                }
            }

            public void requestFailure(ServerExchange exchange)
            {
                // Report the failure to the user.
            }

            public void requestHalted()
            {
                // Request was stopped.
            }   
        }
    }        
}

Retrieving an address for geographic coordinates by using reverse geocoding

Your app can use the ReverseGeocoder class to retrieve a human-readable name for a location, such as a street address, city, or country, by using a set of geographic coordinates.

When you send a reverse geocoding request, you can specify the administrative boundary that you want to receive information for (for example, street address, city, or country). The ReverseGeocodeExchange class contains the following constants that you can use to specify the level of administrative boundary.

  • ADDRESS: Returns the street address.
  • CITY: Returns the city.
  • COUNTRY: Returns the country.
  • MCC: Returns the mobile country code.
  • POSTAL: Returns the postal code or zip code.
  • PROVINCE_STATE: Returns the province or state.
  • TIME_ZONE_ID: Returns the time zone.

In situations where precision is essential, you might want to request a street address. In other situations, you might only need the city or country name.

There might be cases where your app sends a reverse geocoding request but doesn't receive the expected data in return. For example, if your app sends a request using the ADDRESS administrative boundary, and the geographic location is outside the city limits, the reverse geocoding server might not be able to locate a specific street address. In this case, only the state or province name might be returned to the app.

The results of reverse geocoding requests are added to a cache on the device, except when the request was for a precise street address. When you initiate a reverse geocoding request, the app checks the cache for previous search results before it makes a call to the server, except in those cases that you request a specific address. Reverse geocoding requests can be synchronous or asynchronous.

Specifying the geographic coordinates for a location

MapPoint location = new MapPoint(43.4815, -80.5407);

Sending an asynchronous reverse geocoding request

When you send an asynchronous reverse geocoding request, you must pass in a reference to a class that implements the ServerExchangeCallback interface (represented by the callback variable in the following example). You must also specify the coordinates of the location, the administrative boundary, the bearing of the device, and the length of time before the request times out. When you invoke ReverseGeocoder.reverseGeocode(), the app sends the request to the geocoding server and calls the appropriate ServerExchangeCallback method when it has a result.

int bearing = 1;
int timeout = 0;
MyServerExchangeCallback callback = new MyServerExchangeCallback();

try
{
    ReverseGeocoder.getInstance().reverseGeocode(callback, location, 
            ReverseGeocodeExchange.ADDRESS, bearing, timeout);
} 
catch (ReverseGeocodeException e)
{
    // Do something with the exception
}

To create a class that implements the ServerExchangeCallback interface, there are three methods that you must include: requestSuccess(), requestFailure(), and requestHalted(). When a reverse geocoding request is completed, your app invokes one of these methods depending on the result of the request.

A successful reverse geocoding request returns a ReverseGeocodeExchange object which contains a Vector of search results that you can access by invoking ReverseGeocodeExchange.getResults(). The Vector contains a net.rim.device.api.lbs.maps.model.MapLocation object that has details about a location, such as the location name, a description, and the coordinates. For the complete list of properties, see the MapLocation class.

public class MyServerExchangeCallback implements ServerExchangeCallback
{
    public void requestSuccess(ServerExchange exchange)
    {
        if(exchange instanceof ReverseGeocodeExchange)
        {
            // Casts the Exchange object to a ReverseGeocodeExchange 
            // object and retrieves the Vector of results.
            ReverseGeocodeExchange reverseGeocodeExchange = 
                    (ReverseGeocodeExchange)exchange;
            Vector results = reverseGeocodeExchange.getResults();

            // Do something with the results
        }
    }

    public void requestFailure(ServerExchange exchange)
    {
        // Inform the user of the failure
    }

    public void requestHalted()
    {
        // Invoked when the request is stopped
    }
}

Sending a synchronous reverse geocoding request

For synchronous reverse geocoding requests, your app does not have to implement the ServerExchangeCallback interface. To initiate a synchronous geocoding request, you must specify null as the argument instead of passing in a reference to a class that implements ServerExchangeCallback. When you run a synchronous geocoding request, you must verify the result of the request manually. Typically, you should run synchronous geocoding requests on a thread other than the UI thread, otherwise users won't be able to interact with the UI during the request.

try
{ 
    ReverseGeocodeExchange exchange = ReverseGeocoder.getInstance().reverseGeocode(
            callback, location, ReverseGeocodeExchange.ADDRESS, bearing, timeout);
                    
    // Check if the request was successful
    if(exchange.getExceptionList().size() == 0)
    {
        if(exchange instanceof ReverseGeocodeExchange)
        {
            // Casts the Exchange object to a ReverseGeocodeExchange 
            // object and retrieves the Vector of results.
	           ReverseGeocodeExchange reverseGeocodeExchange = 
                    (ReverseGeocodeExchange)exchange;
            Vector results = reverseGeocodeExchange.getResults();

            // Do something with the results
        }
    }
    else
    {
        // Inform the user of the failure
    }
}
catch(GeocodeException e)
{
    // Do something with the exception
}

Code sample: Retrieving an address for geographic coordinates by using reverse geocoding

The following code sample demonstrates how to retrieve an address name by using an asynchronous reverse geocoding request. The request specifies that the server must return a precise street address, which is indicated by the ReverseGeocodeExchange.ADDRESS parameter that is passed into geocode(). When the app receives the results of the request, it displays the address on the screen.

import net.rim.device.api.lbs.maps.MapDimensions;
import net.rim.device.api.lbs.maps.model.*;
import net.rim.device.api.lbs.maps.server.*;
import net.rim.device.api.lbs.maps.server.exchange.*;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.system.*;
import java.util.Vector;

public class ReverseGeocodingDemo extends UiApplication
{
    public static void main(String[] args)
    {
        ReverseGeocodingDemo app = new ReverseGeocodingDemo();
        app.enterEventDispatcher();
    }
      
    public ReverseGeocodingDemo()
    {
        pushScreen(new ReverseGeocodingDemoScreen());
    }
          
    public class ReverseGeocodingDemoScreen extends MainScreen
    {
        private LabelField _resultsField;
        
        public ReverseGeocodingDemoScreen()
        {
            setTitle("Reverse Geocoding Demo");
            
            _resultsField = new LabelField();
            add(_resultsField);  
           
            // Location for the request.
            MapPoint origin = new MapPoint(43.4815, -80.5407);
            
            // Create an instance of the class that implements 
            // ServerExchangeCallback.
            MyServerExchangeCallback callback = new MyServerExchangeCallback();
                        
            try
            {
                // Initiate the reverse geocoding request.
                ReverseGeocoder.getInstance().reverseGeocode(callback, origin, 
                        ReverseGeocodeExchange.ADDRESS, 1, 0);
            } 
            catch (ReverseGeocodeException e)
            {
                // Do something with the exception.
            }   
        }
        
        public class MyServerExchangeCallback implements ServerExchangeCallback
        {
            public void requestSuccess(ServerExchange exchange)
            {
                // StringBuffer used to display the location information from 
                // the request.
                StringBuffer buffer = new StringBuffer();

                if(exchange instanceof ReverseGeocodeExchange)
                {
                    // Cast the Exchange object to a ReverseGeocodeExchange 
                    // object and retrieve the Vector of results.
                    ReverseGeocodeExchange reverseGeocodeExchange = 
                            (ReverseGeocodeExchange)exchange;
                    Vector results = reverseGeocodeExchange.getResults();

                    // Iterate through each MapLocation object in the Vector.
                    for(int i = 0; i < results.size(); i++)
                    {
                        // Retrieve info from the MapLocation object
                        // and append it to the StringBuffer.
                        MapLocation location = (MapLocation) results.elementAt(i);
                        buffer.append("Name: ").append(location.getName())
                                .append('\n');
                        buffer.append("Desc: ").append(location.getDescription())
                                .append('\n');
                        buffer.append("Addr: ").append(location.getData
                                (MapLocation.LBS_LOCATION_STREET_ADDRESS_KEY))
                                .append('\n');
                        buffer.append("City: ").append(location.getData
                                (MapLocation.LBS_LOCATION_CITY_KEY))
                                .append('\n');
                        buffer.append("County: ").append(location.getData
                                (MapLocation.LBS_LOCATION_COUNTY_KEY))
                                .append('\n');
                        buffer.append("Zip: ").append(location.getData
                                (MapLocation.LBS_LOCATION_POSTAL_CODE_KEY))
                                .append('\n');
                    }
                    
                    // Take control of the UI thread and display the location 
                    // information on the screen.
                    synchronized(UiApplication.getEventLock())
                    {
                        _resultsField.setText(buffer.toString());
                    }        
                }
            }

            public void requestFailure(ServerExchange exchange)
            {
                // Report the failure to the user.
            }

            public void requestHalted()
            {
                // Request was stopped.
            }   
        }
    }
}