Android 地理编码器在某些设备上的行为不同
Android Geocoder behaves different on some devices
我有下面的代码,它在某些设备上运行良好,在其他设备上运行良好
getFromLocationName return 大小为 0 的列表。
例如,在 Nexus 6p
中 return 是正确的结果
在 Meizu MX5
中,它 return 是一个大小为 0 的列表。
我对两台设备拥有相同的权限和 GPS 启用。
Android Nexus 6p
上的版本是 7.1.2,Meizu MX5
上的版本是 5.1
Geocoder geocoder = new Geocoder(context);
List<Address> addresses = geocoder.getFromLocationName(place, 3);
备注:
- place 是用户输入的位置(字符串)。
- 地理编码器来自android.location.Geocoder;
那么为什么不同呢?与设备上的 Android 版本有关吗?
Android 中的地理编码器在所有设备上的行为确实不同。我已经使用以下设备测试了地理编码器:
- 三星(Android 4.4 和 5.1)
- 联想(Android 5.0)
- 体内 (Android 6.0.1)
- Andromax (Android 5.1.1)
- 小米 (Android 5.1)
所有返回列表的设备,但小米,它 returns 零列表。所以,我们不能依赖 Geocoder。解决方案是使用 Google Geocoding API 创建我们自己的 Geocoder 实现,并在列表 returns 0 时使用它。
这里是 Geocoder 的实现(我是从 SO 上找到的,但不记得出处了),可以像使用 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;
}
}
注意 Android Geocoder API.
中没有的每日配额
我有下面的代码,它在某些设备上运行良好,在其他设备上运行良好 getFromLocationName return 大小为 0 的列表。
例如,在 Nexus 6p
中 return 是正确的结果
在 Meizu MX5
中,它 return 是一个大小为 0 的列表。
我对两台设备拥有相同的权限和 GPS 启用。
Android Nexus 6p
上的版本是 7.1.2,Meizu MX5
上的版本是 5.1
Geocoder geocoder = new Geocoder(context);
List<Address> addresses = geocoder.getFromLocationName(place, 3);
备注:
- place 是用户输入的位置(字符串)。
- 地理编码器来自android.location.Geocoder;
那么为什么不同呢?与设备上的 Android 版本有关吗?
Android 中的地理编码器在所有设备上的行为确实不同。我已经使用以下设备测试了地理编码器:
- 三星(Android 4.4 和 5.1)
- 联想(Android 5.0)
- 体内 (Android 6.0.1)
- Andromax (Android 5.1.1)
- 小米 (Android 5.1)
所有返回列表的设备,但小米,它 returns 零列表。所以,我们不能依赖 Geocoder。解决方案是使用 Google Geocoding API 创建我们自己的 Geocoder 实现,并在列表 returns 0 时使用它。
这里是 Geocoder 的实现(我是从 SO 上找到的,但不记得出处了),可以像使用 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;
}
}
注意 Android Geocoder API.
中没有的每日配额