Reverse Geocoding with Yahoo API
A very popular group of services in smartphones are the Location Based Services. Geocoding is the process that finds the geographic coordinates ,in latitude and longitude, from other geographical data, like street addresses or postal codes.
In this tutorial we are going to talk about reverse Geocoding. That is the process that uses the user’s coordinates and finds out street addresses an nearby points of interest. For this tutorial we are going to Use Yahoo! PlacaFinder which in an excellent API for reverse Geocoding. To fully use the API, you are going to need a kay. But for this tutorial this won’t be necessary.
In short, in order to do reverse Geocoding you will :
- Bundle a button with an OnClickListener, that invokes
performReverseGeocodingInBackground
method, which retrieves the current location. - Perform the data retrieval using the information from the Location object, using a class that extend AsyncTasks, to enable easy use of the UI thread because Internet communication activities are time consuming
- Construct a GeoCoder class that makes use of the Yahoo API
- Use an
HttpRetriever
and anXmlParser
get the data from Yahoo and parse it. - Format the query string concatenating the user’s coordinates to the Yahoo API base url
- Then use a
DefaultHTPClient
to perform the HTTP request/response.
package com.javacodegeeks.android.lbs; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import com.javacodegeeks.android.lbs.model.GeoCodeResult; import com.javacodegeeks.android.lbs.services.GeoCoder; public class LbsGeocodingActivity extends Activity { private static final long MINIMUM_DISTANCE_CHANGE_FOR_UPDATES = 1; // in Meters private static final long MINIMUM_TIME_BETWEEN_UPDATES = 1000; // in Milliseconds private GeoCoder geoCoder = new GeoCoder(); protected LocationManager locationManager; protected Location currentLocation; protected Button retrieveLocationButton; protected Button reverseGeocodingButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); retrieveLocationButton = (Button) findViewById(R.id.retrieve_location_button); reverseGeocodingButton = (Button) findViewById(R.id.reverse_geocoding_button); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MINIMUM_TIME_BETWEEN_UPDATES, MINIMUM_DISTANCE_CHANGE_FOR_UPDATES, new MyLocationListener() ); retrieveLocationButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showCurrentLocation(); } }); reverseGeocodingButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { performReverseGeocodingInBackground(); } }); } protected void performReverseGeocodingInBackground() { showCurrentLocation(); new ReverseGeocodeLookupTask().execute((Void[])null); } protected void showCurrentLocation() { currentLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (currentLocation != null) { String message = String.format( "Current Location n Longitude: %1$s n Latitude: %2$s", currentLocation.getLongitude(), currentLocation.getLatitude() ); Toast.makeText(LbsGeocodingActivity.this, message, Toast.LENGTH_LONG).show(); } } private class MyLocationListener implements LocationListener { public void onLocationChanged(Location location) { String message = String.format( "New Location n Longitude: %1$s n Latitude: %2$s", location.getLongitude(), location.getLatitude() ); Toast.makeText(LbsGeocodingActivity.this, message, Toast.LENGTH_LONG).show(); } public void onStatusChanged(String s, int i, Bundle b) { Toast.makeText(LbsGeocodingActivity.this, "Provider status changed", Toast.LENGTH_LONG).show(); } public void onProviderDisabled(String s) { Toast.makeText(LbsGeocodingActivity.this, "Provider disabled by the user. GPS turned off", Toast.LENGTH_LONG).show(); } public void onProviderEnabled(String s) { Toast.makeText(LbsGeocodingActivity.this, "Provider enabled by the user. GPS turned on", Toast.LENGTH_LONG).show(); } } public class ReverseGeocodeLookupTask extends AsyncTask <Void, Void, GeoCodeResult> { private ProgressDialog progressDialog; @Override protected void onPreExecute() { this.progressDialog = ProgressDialog.show( LbsGeocodingActivity.this, "Please wait...contacting Yahoo!", // title "Requesting reverse geocode lookup", // message true // indeterminate ); } @Override protected GeoCodeResult doInBackground(Void... params) { return geoCoder.reverseGeoCode(currentLocation.getLatitude(), currentLocation.getLongitude()); } @Override protected void onPostExecute(GeoCodeResult result) { this.progressDialog.cancel(); Toast.makeText(LbsGeocodingActivity.this, result.toString(), Toast.LENGTH_LONG).show(); } } }
package com.javacodegeeks.android.lbs.services; import com.javacodegeeks.android.lbs.model.GeoCodeResult; public class GeoCoder { private static final String YAHOO_API_BASE_URL = "http://where.yahooapis.com/geocode?q=%1$s,+%2$s&gflags=R&appid=[yourappidhere]"; private HttpRetriever httpRetriever = new HttpRetriever(); private XmlParser xmlParser = new XmlParser(); public GeoCodeResult reverseGeoCode(double latitude, double longitude) { String url = String.format(YAHOO_API_BASE_URL, String.valueOf(latitude), String.valueOf(longitude)); String response = httpRetriever.retrieve(url); return xmlParser.parseXmlResponse(response); } }
package com.javacodegeeks.android.lbs.services; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import android.util.Log; public class HttpRetriever { private final String TAG = getClass().getSimpleName(); private DefaultHttpClient client = new DefaultHttpClient(); public String retrieve(String url) { HttpGet get = new HttpGet(url); try { HttpResponse getResponse = client.execute(get); HttpEntity getResponseEntity = getResponse.getEntity(); if (getResponseEntity != null) { String response = EntityUtils.toString(getResponseEntity); Log.d(TAG, response); return response; } } catch (IOException e) { e.printStackTrace(); } return null; } }
package com.javacodegeeks.android.lbs.services; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import android.util.Log; import com.javacodegeeks.android.lbs.model.GeoCodeResult; public class XmlParser { private final String TAG = getClass().getSimpleName(); public GeoCodeResult parseXmlResponse(String response) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(new StringReader(response))); NodeList resultNodes = doc.getElementsByTagName("Result"); Node resultNode = resultNodes.item(0); NodeList attrsList = resultNode.getChildNodes(); GeoCodeResult result = new GeoCodeResult(); for (int i=0; i < attrsList.getLength(); i++) { Node node = attrsList.item(i); Node firstChild = node.getFirstChild(); if ("line1".equalsIgnoreCase(node.getNodeName()) && firstChild!=null) { result.line1 = firstChild.getNodeValue(); } if ("line2".equalsIgnoreCase(node.getNodeName()) && firstChild!=null) { result.line2 = firstChild.getNodeValue(); } if ("line3".equalsIgnoreCase(node.getNodeName()) && firstChild!=null) { result.line3 = firstChild.getNodeValue(); } if ("line4".equalsIgnoreCase(node.getNodeName()) && firstChild!=null) { result.line4 = firstChild.getNodeValue(); } } Log.d(TAG, result.toString()); return result; } catch (Exception e) { e.printStackTrace(); } return null; } }
package com.javacodegeeks.android.lbs.model; public class GeoCodeResult { public String line1; public String line2; public String line3; public String line4; @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Location:"); if (line1!=null) builder.append("-"+line1); if (line2!=null) builder.append("-"+line2); if (line3!=null) builder.append("-"+line3); if (line4!=null) builder.append("-"+line4); return builder.toString(); } }
This was an example on how to perform Reverse Geocoding with Yahoo API.
Related Article: