Google Geocoder Service Is Unavaliable (Coordinates to Address)

Google Geocoder service is unavaliable (Coordinates to address)

The common answer to this problem is that you have to restart your device.

Surely you cannot tell your users to restart device in order for your app to function, so my solution was to use a HTTP fallback, here is the AsyncTask I use in my code.

You will have to modify it for your situation, as I lookup address from position and not the other way around.

    private class GetAddressPositionTask extends
AsyncTask<String, Integer, LatLng> {

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

@Override
protected LatLng doInBackground(String... plookupString) {

String lookupString = plookupString[0];
final String lookupStringUriencoded = Uri.encode(lookupString);
LatLng position = null;

// best effort zoom
try {
if (geocoder != null) {
List<Address> addresses = geocoder.getFromLocationName(
lookupString, 1);
if (addresses != null && !addresses.isEmpty()) {
Address first_address = addresses.get(0);
position = new LatLng(first_address.getLatitude(),
first_address.getLongitude());
}
} else {
Log.e(TAG, "geocoder was null, is the module loaded? "
+ isLoaded);
}

} catch (IOException e) {
Log.e(TAG, "geocoder failed, moving on to HTTP");
}
// try HTTP lookup to the maps API
if (position == null) {
HttpGet httpGet = new HttpGet(
"http://maps.google.com/maps/api/geocode/json?address="
+ lookupStringUriencoded + "&sensor=true");
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();

try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}

JSONObject jsonObject = new JSONObject();
try {
// Log.d("MAPSAPI", stringBuilder.toString());

jsonObject = new JSONObject(stringBuilder.toString());
if (jsonObject.getString("status").equals("OK")) {
jsonObject = jsonObject.getJSONArray("results")
.getJSONObject(0);
jsonObject = jsonObject.getJSONObject("geometry");
jsonObject = jsonObject.getJSONObject("location");
String lat = jsonObject.getString("lat");
String lng = jsonObject.getString("lng");

// Log.d("MAPSAPI", "latlng " + lat + ", "
// + lng);

position = new LatLng(Double.valueOf(lat),
Double.valueOf(lng));
}

} catch (JSONException e) {
Log.e(TAG, e.getMessage(), e);
}

}
return position;
}

@Override
protected void onPostExecute(LatLng result) {
Log.i("GEOCODE", result.toString());
super.onPostExecute(result);
}

};

Google geocoding service returns response for fake address

There isn't any way for the geocoder to let you know if it thinks you had a typo. I agree with Saul's answer, that your best bet is to check your query against the response.

I just wanted to point out that you'll have to check several elements of your input against several of the response values, in order to find the elements that should match up. In this case, "Beaverton" was found inside of "DependentLocalityName".

<?xml version="1.0" encoding="UTF-8" ?>
<kml xmlns="http://earth.google.com/kml/2.0"><Response>
<name>Beverton, Ontario, Canada</name>
<Status>
<code>200</code>
<request>geocode</request>
</Status>
<Placemark id="p1">

<address>Beaverton, Brock, ON, Canada</address>
<AddressDetails Accuracy="4" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"><Country><CountryNameCode>CA</CountryNameCode><CountryName>Canada</CountryName><AdministrativeArea><AdministrativeAreaName>ON</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Durham Regional Municipality</SubAdministrativeAreaName><Locality><LocalityName>Brock</LocalityName><DependentLocality><DependentLocalityName>Beaverton</DependentLocalityName></DependentLocality></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails>
<ExtendedData>
<LatLonBox north="44.4502166" south="44.4183470" east="-79.1199562" west="-79.1839858" />
</ExtendedData>

<Point><coordinates>-79.1519710,44.4342840,0</coordinates></Point>
</Placemark>
</Response></kml>

Update:

This may be impossible to actually implement. If your input is "Beverton, Ontario, Canada", how do you know which of those three words to check for? Two of them will match up just fine. What if they're entered in a different order?

Can only obtain address using GeoCoder with WiFi, not mobile internet (LTE)

I couldn't figure out how to get geocoder working using mobile internet so I resorted to using google maps api, which works over wifi and mobile internet. Here is my implementation:

try {
URL url = new URL("http://maps.googleapis.com/maps/api/geocode/json?latlng=" +
latitude + "," + longitude + "&sensor=true");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.connect();

jsonResult = inputStreamToString(conn.getInputStream()).toString();
JSONObject jsonResponse = new JSONObject(jsonResult);

Log.d("json result", "Geocoder Status: " + jsonResponse.getString("status"));
if("OK".equalsIgnoreCase(jsonResponse.getString("status"))) {
JSONArray addressComponents = ((JSONArray)jsonResponse.get("results")).getJSONObject(0).getJSONArray("address_components");
for (int i = 0; i < addressComponents.length(); i++) {
String addressComponent = ((JSONArray) ((JSONObject) addressComponents.get(i)).get("types")).getString(0);
if (addressComponent.equals("locality")) {
locality = ((JSONObject) addressComponents.get(i)).getString("long_name");
}
if (addressComponent.equals("administrative_area_level_1")) {
admin1 = ((JSONObject) addressComponents.get(i)).getString("long_name");
}
if (addressComponent.equals("country")) {
countryCode = ((JSONObject) addressComponents.get(i)).getString("short_name");
}
}
Log.d("json result", locality + "." + admin1 + "." + countryCode);
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}

private StringBuilder inputStreamToString(InputStream is) {
String rLine = "";
StringBuilder answer = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
while ((rLine = rd.readLine()) != null) {
answer.append(rLine);
}
} catch (IOException e) {
// e.printStackTrace();
Toast.makeText(mContext.getApplicationContext(),
"Error..." + e.toString(), Toast.LENGTH_LONG).show();
}
return answer;
}

Why is Android Geocoder throwing a Service not Available exception?

I asked Google's Reto Meier to confirm my theory was correct and he said "Correct. The Geocoder is part of the Google API add-on that isn't part of the AOSP."

So any device that doesn't come with the Play Store, GMail apps etc… will also be missing the Geocoder back-end.

Service not available in geoCoder

Here is my way to get the address even if Geocoder failed... but first let me explain my own experience with Geocoder:

For some unknown reason, Geocoder works fine then, suddenly break!.

What I observed is that, after a while (can be days), Geocoder start to throw "Service not available" exception.

EDIT-> As mentioned by Christian, the exception is thrown even is isPresent() returns true.<-EDIT END

Really weird since it was working fine before and no configuration changed occurred:

  • same device
  • same Android version
  • same app
  • same manifest
  • WIFI up and running, Device location feature enabled in settings

Of course, something changed, but, for the time being, we don't know exactly what.
There is a bug opened about that: Issue 38009: 4.1.1 Geocoder throwing exception: IOException: Service not Available

Last post on this thread (ATTOW) "Probably it's periodically reproducible in android 4.0.x + target API x"

As a workaround, you can use Google Map

Here is my GeocoderHelper class that provides a 'Google Map' B Plan in case Geocoder start to fails.
In my case, I am just interested in CityName, but you can basically get any data availalbe in google map JSON output

Usage:

new GeocoderHelper().fetchCityName(context, location);
Then do somthing in onPostExecute() of example code (send broadcast, invoke listener method, set a textView text, whatever)

GeocoderHelper Class:

package com.<your_package>.location;

import java.util.List;
import java.util.Locale;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.util.Log;

public class GeocoderHelper
{
private static final AndroidHttpClient ANDROID_HTTP_CLIENT = AndroidHttpClient.newInstance(GeocoderHelper.class.getName());

private boolean running = false;

public void fetchCityName(final Context contex, final Location location)
{
if (running)
return;

new AsyncTask<Void, Void, String>()
{
protected void onPreExecute()
{
running = true;
};

@Override
protected String doInBackground(Void... params)
{
String cityName = null;

if (Geocoder.isPresent())
{
try
{
Geocoder geocoder = new Geocoder(contex, Locale.getDefault());
List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
if (addresses.size() > 0)
{
cityName = addresses.get(0).getLocality();
}
}
catch (Exception ignored)
{
// after a while, Geocoder start to trhow "Service not availalbe" exception. really weird since it was working before (same device, same Android version etc..
}
}

if (cityName != null) // i.e., Geocoder succeed
{
return cityName;
}
else // i.e., Geocoder failed
{
return fetchCityNameUsingGoogleMap();
}
}

// Geocoder failed :-(
// Our B Plan : Google Map
private String fetchCityNameUsingGoogleMap()
{
String googleMapUrl = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + location.getLatitude() + ","
+ location.getLongitude() + "&sensor=false&language=fr";

try
{
JSONObject googleMapResponse = new JSONObject(ANDROID_HTTP_CLIENT.execute(new HttpGet(googleMapUrl),
new BasicResponseHandler()));

// many nested loops.. not great -> use expression instead
// loop among all results
JSONArray results = (JSONArray) googleMapResponse.get("results");
for (int i = 0; i < results.length(); i++)
{
// loop among all addresses within this result
JSONObject result = results.getJSONObject(i);
if (result.has("address_components"))
{
JSONArray addressComponents = result.getJSONArray("address_components");
// loop among all address component to find a 'locality' or 'sublocality'
for (int j = 0; j < addressComponents.length(); j++)
{
JSONObject addressComponent = addressComponents.getJSONObject(j);
if (result.has("types"))
{
JSONArray types = addressComponent.getJSONArray("types");

// search for locality and sublocality
String cityName = null;

for (int k = 0; k < types.length(); k++)
{
if ("locality".equals(types.getString(k)) && cityName == null)
{
if (addressComponent.has("long_name"))
{
cityName = addressComponent.getString("long_name");
}
else if (addressComponent.has("short_name"))
{
cityName = addressComponent.getString("short_name");
}
}
if ("sublocality".equals(types.getString(k)))
{
if (addressComponent.has("long_name"))
{
cityName = addressComponent.getString("long_name");
}
else if (addressComponent.has("short_name"))
{
cityName = addressComponent.getString("short_name");
}
}
}
if (cityName != null)
{
return cityName;
}
}
}
}
}
}
catch (Exception ignored)
{
ignored.printStackTrace();
}
return null;
}

protected void onPostExecute(String cityName)
{
running = false;
if (cityName != null)
{
// Do something with cityName
Log.i("GeocoderHelper", cityName);
}
};
}.execute();
}
}

Hope this will help.

How to get complete address from latitude and longitude?

Geocoder geocoder;
List<Address> addresses;
geocoder = new Geocoder(this, Locale.getDefault());

addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5

String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName(); // Only if available else return NULL

For more info of available details, Look at Android-Location-Address



Related Topics



Leave a reply



Submit