我試圖找到一個街道地址w/o城市的位置(緯度/經度) - 比如「123 Main St.」 - 距離當前位置最近。此功能內置於Google地圖應用以及iOS地圖api中,因此發現它缺少Android版本令人驚訝 - 例如,調用Geocoder.getFromLocation()並讓平臺插入一個參考點。我已經嘗試了幾種解決方案,以下是最好的,但仍然感覺自卑。從Android的地址獲取位置(經度/緯度)沒有城市的地址
我使用左下角和右上角座標調用Geocoder.getFromLocationName()。調用以當前位置周圍的一個10kmx10km區域開始,並重復(30x30,100x100,然後沒有邊框參數),直到返回一些地址。當返回多個地址時,計算並使用最近的:
更新:此方法好像對於容易找到的邊界外的地址是低效的。例如。從西海岸搜索「紐約紐約」或「波士頓」 - 需要3次有界和1次無界調用Geocoder.getFromLocation()。然而,沒有特別說明的是,在第一次通話時,紐約證券交易所和波士頓正確的經濟緯度/經濟回報率將在這裏以最嚴格的界限返回。谷歌正在聰明,無視我們的界限。這可能會導致一些問題,但對於這種方法非常有用。
package com.puurbuy.android;
import java.io.IOException;
import java.util.List;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.AsyncTask;
import android.util.Log;
public class GeocoderRunner extends AsyncTask<String, Void, Address> {
final static double LON_DEG_PER_KM = 0.012682308180089;
final static double LAT_DEG_PER_KM =0.009009009009009;
final static double[] SEARCH_RANGES = {10, 50,800,-1}; //city, region, state, everywhere
private Context mContext;
private GeocoderListener mListener;
private Location mLocation;
public GeocoderRunner(Context context, Location location,
GeocoderListener addressLookupListener) {
mContext = context;
mLocation = location;
mListener = addressLookupListener;
}
@Override
protected Address doInBackground(String... params) {
Geocoder geocoder = new Geocoder(mContext);
List<Address> addresses = null;
//reference location TODO handle null
double lat = mLocation.getLatitude();
double lon = mLocation.getLongitude();
int i = 0;
try {
//loop through SEARCH_RANGES until addresses are returned
do{
//if range is -1, call getFromLocationName() without bounding box
if(SEARCH_RANGES[i] != -1){
//calculate bounding box
double lowerLeftLatitude = translateLat(lat,-SEARCH_RANGES[i]);
double lowerLeftLongitude = translateLon(lon,SEARCH_RANGES[i]);
double upperRightLatitude = translateLat(lat,SEARCH_RANGES[i]);
double upperRightLongitude = translateLon(lon,-SEARCH_RANGES[i]);
addresses = geocoder.getFromLocationName(params[0], 5, lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude);
} else {
//last resort, try unbounded call with 20 result
addresses = geocoder.getFromLocationName(params[0], 20);
}
i++;
}while((addresses == null || addresses.size() == 0) && i < SEARCH_RANGES.length);
} catch (IOException e) {
Log.i(this.getClass().getSimpleName(),"Gecoder lookup failed! " +e.getMessage());
}
if(addresses == null ||addresses.size() == 0)
return null;
//If multiple addresses were returned, find the closest
if(addresses.size() > 1){
Address closest = null;
for(Address address: addresses){
if(closest == null)
closest = address;
else
closest = getClosest(mLocation, closest,address);//returns the address that is closest to mLocation
}
return closest;
}else
return addresses.get(0);
}
@Override
protected void onPostExecute(Address address) {
if(address == null)
mListener.lookupFailed();
else
mListener.addressReceived(address);
}
//Listener callback
public interface GeocoderListener{
public void addressReceived(Address address);
public void lookupFailed();
}
//HELPER Methods
private static double translateLat(double lat, double dx){
if(lat > 0)
return (lat + dx*LAT_DEG_PER_KM);
else
return (lat - dx*LAT_DEG_PER_KM);
}
private static double translateLon(double lon, double dy){
if(lon > 0)
return (lon + dy*LON_DEG_PER_KM);
else
return (lon - dy*LON_DEG_PER_KM);
}
private static Address getClosest(Location ref, Address address1, Address address2){
double xO = ref.getLatitude();
double yO = ref.getLongitude();
double x1 = address1.getLatitude();
double y1 = address1.getLongitude();
double x2 = address2.getLatitude();
double y2 = address2.getLongitude();
double d1 = distance(xO,yO,x1,y1);
double d2 = distance(xO,yO,x2,y2);
if(d1 < d2)
return address1;
else
return address2;
}
private static double distance(double x1, double y1, double x2, double y2){
return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
}
或許這是最好的解決辦法,但我不知道是否有一種方法在單個調用做到這一點。
Geocoder.getFromLocationName()的Javadoc建議請求1-5個結果。有超過5個地方與「123 Main St.」相匹配我剛剛執行了這個任務,得到了Van Buren ME,Madawaska ME,紐約布法羅,紐約伍斯特和紐約州Schenevus。我在加利福尼亞州,可能不是我在找什麼。 – nathanielwolf
是的,當使用「推薦」5結果時,我的結果不好。因爲如果有100個「主要」街道,那麼您很可能會在前5箇中獲得所需的結果。所以,只需獲得所有結果 - 這將花費大量時間 - 然後在AsyncTask中完成。 – Jin35
無論maxResults參數如何,Geocoder.getFromLocationName()最多返回20個結果。見下文。 – nathanielwolf