1

I have the below code, it works perfectly on some devices and in others the function getFromLocationName return a list with size 0.

For example, in Nexus 6p it returns the correct result and in Meizu MX5 it returns a list with size 0.

I have the same permissions and GPS enable for both devices. Android version on the Nexus 6p is 7.1.2 and on Meizu MX5 is 5.1

  Geocoder geocoder = new Geocoder(context);
  List<Address> addresses = geocoder.getFromLocationName(place, 3);

Notes:

  1. place is the location the user entered (String).
  2. Geocoder is from android.location.Geocoder;

So why the difference? Is it related to the Android version on the devices?

Dinal Koyani
  • 455
  • 3
  • 6
Elior
  • 3,178
  • 6
  • 37
  • 67
  • 2
    the return value is described in javadocs as: `"a list of Address objects. Returns null or empty list if no matches were found or there is no backend service available."` – pskink Nov 02 '17 at 08:02
  • as pskink stated it is not necessary that you will get address for all location. You can still get country and state too if available – Vivek Mishra Nov 02 '17 at 08:09
  • ok. I forgot to mention that on both devices I used the same location. So why on the Nexus 6p it success and on the Meizu it doesn't? As you said if their is a service that returns the result, it means that the meizu should return the same result as the nexus, no? – Elior Nov 02 '17 at 08:15
  • ok so `Geocoder` dosc say: `"The Geocoder class requires a backend service that is not included in the core android framework. The Geocoder query methods will return an empty list if there no backend service in the platform. Use the isPresent() method to determine whether a Geocoder implementation exists."` did you check `isPresent()` return value? – pskink Nov 02 '17 at 08:16
  • i'll check it. thanks :) So I guess that if I want it to be available on all devices, I should use the google maps geocoding api – Elior Nov 02 '17 at 08:19
  • @pskink thanks, I've checked and isPresent() returns true on the Meizu, so it means that getLocationFromName is implemented. They also says that lack of network connectivity may cause to this method to return empty list or null. so I guess this is the problem on the Meizu.. – Elior Nov 02 '17 at 08:28
  • yes, indeed: `"Lack of network connectivity may still cause these methods to return null or empty lists."` - it can be the reason you have the empty list – pskink Nov 02 '17 at 08:31
  • it's weird... the device has full signal :) thanks for your help. I think I'll try to use the google maps geocoding api, to see if it works – Elior Nov 02 '17 at 08:38
  • but still "Mobile Data" can be disabled... – pskink Nov 02 '17 at 08:39
  • no I've checked it before, I tried the geocoder.. it is enabled – Elior Nov 02 '17 at 08:42
  • anyway.. thanks for your help ! – Elior Nov 02 '17 at 08:43

1 Answers1

3

Geocoder in Android is really don't have the same behaviour on all devices. I have tested the Geocoder with the following devices:

  • Samsung (Android 4.4 and 5.1)
  • Lenovo (Android 5.0)
  • Vivo (Android 6.0.1)
  • Andromax (Android 5.1.1)
  • Xiaomi (Android 5.1)

All the devices returning the list but Xiaomi, it returns zero lists. So, we can't depend on Geocoder. The solution is to create our own Geocoder implementation using Google Geocoding API and use it whenever the list returns 0.

Here the implementation of Geocoder (I found it from SO, but can't remember the source) which can be used exatly like using the Geocoder:

import android.location.Address;
import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class MyGeocoder {

  public static final String TAG = MyGeocoder.class.getSimpleName();

  static OkHttpClient client = new OkHttpClient();

  public static List<Address> getFromLocation(double lat, double lng, int maxResult) {

    String address = String.format(Locale.US,
        "https://maps.googleapis.com/maps/api/geocode/json?latlng=%1$f,%2$f&sensor=false&language="
            + Locale.getDefault().getCountry(), lat, lng);
    Log.d(TAG, "address = " + address);
    Log.d(TAG, "Locale.getDefault().getCountry() = " + Locale.getDefault().getCountry());

    return getAddress(address, maxResult);

  }

  public static List<Address> getFromLocationName(String locationName, int maxResults)  {

    String address = null;
    try {
      address = "https://maps.google.com/maps/api/geocode/json?address=" + URLEncoder.encode(locationName,
          "UTF-8") + "&ka&sensor=false";
      return getAddress(address, maxResults);
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    return null;
  }

  private static List<Address> getAddress(String url, int maxResult) {
    List<Address> retList = null;

    Request request = new Request.Builder().url(url)
        .header("User-Agent", "OkHttp Headers.java")
        .addHeader("Accept", "application/json; q=0.5")
        .build();
    try {
      Response response = client.newCall(request).execute();
      String responseStr = response.body().string();
      JSONObject jsonObject = new JSONObject(responseStr);

      retList = new ArrayList<Address>();

      if ("OK".equalsIgnoreCase(jsonObject.getString("status"))) {
        JSONArray results = jsonObject.getJSONArray("results");
        if (results.length() > 0) {
          for (int i = 0; i < results.length() && i < maxResult; i++) {
            JSONObject result = results.getJSONObject(i);
            Address addr = new Address(Locale.getDefault());

            JSONArray components = result.getJSONArray("address_components");
            String streetNumber = "";
            String route = "";
            for (int a = 0; a < components.length(); a++) {
              JSONObject component = components.getJSONObject(a);
              JSONArray types = component.getJSONArray("types");
              for (int j = 0; j < types.length(); j++) {
                String type = types.getString(j);
                if (type.equals("locality")) {
                  addr.setLocality(component.getString("long_name"));
                } else if (type.equals("street_number")) {
                  streetNumber = component.getString("long_name");
                } else if (type.equals("route")) {
                  route = component.getString("long_name");
                }
              }
            }
            addr.setAddressLine(0, route + " " + streetNumber);

            addr.setLatitude(
                result.getJSONObject("geometry").getJSONObject("location").getDouble("lat"));
            addr.setLongitude(
                result.getJSONObject("geometry").getJSONObject("location").getDouble("lng"));
            retList.add(addr);
          }
        }
      }
    } catch (IOException e) {
      Log.e(TAG, "Error calling Google geocode webservice.", e);
    } catch (JSONException e) {
      Log.e(TAG, "Error parsing Google geocode webservice response.", e);
    }

    return retList;
  }
}

Be aware of the daily quota which didn't happen in Android Geocoder API.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96