location

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 an XmlParser 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:

Byron Kiourtzoglou

Byron is a master software engineer working in the IT and Telecom domains. He is an applications developer in a wide variety of applications/services. He is currently acting as the team leader and technical architect for a proprietary service creation and integration platform for both the IT and Telecom industries in addition to a in-house big data real-time analytics solution. He is always fascinated by SOA, middleware services and mobile development. Byron is co-founder and Executive Editor at Java Code Geeks.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button