从Android中没有城市的地址获取位置(纬度/经度)

从Android中没有城市的地址获取位置(纬度/经度),android,google-geocoder,Android,Google Geocoder,我试图找到一个没有城市的街道地址的位置(纬度/长度),比如“123大街”,离当前位置最近。谷歌地图应用程序和iOS地图api都内置了这一功能,因此发现Android缺少这一功能令人惊讶——例如调用Geocoder.getFromLocation()并让平台插入参考点。我已经尝试了几种解决方案,以下是最好的,但仍然感觉低人一等 我使用左下角和右上角坐标调用Geocoder.getFromLocationName()。从当前位置周围的10kmx10km区域开始进行调用,并重复调用(30x30、100

我试图找到一个没有城市的街道地址的位置(纬度/长度),比如“123大街”,离当前位置最近。谷歌地图应用程序和iOS地图api都内置了这一功能,因此发现Android缺少这一功能令人惊讶——例如调用Geocoder.getFromLocation()并让平台插入参考点。我已经尝试了几种解决方案,以下是最好的,但仍然感觉低人一等

我使用左下角和右上角坐标调用Geocoder.getFromLocationName()。从当前位置周围的10kmx10km区域开始进行调用,并重复调用(30x30、100x100,然后不使用边界框参数),直到返回一些地址。返回多个地址时,将计算并使用最近的地址:

更新:这种方法对于边界之外的容易找到的地址似乎效率低下。例如,从西海岸搜索“纽约、纽约”或“波士顿”-需要对Geocoder.getFromLocation()进行3次有界调用和1次无界调用。然而,出乎意料的是,在第一次通话中,纽约和波士顿返回了正确的lat/lng,加州的限制最为严格。谷歌很聪明,忽略了我们的限制。这可能会给一些人带来问题,但对于这种方法来说是非常好的

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) );
}
package com.puurbuy.android;
导入java.io.IOException;
导入java.util.List;
导入android.content.Context;
导入android.location.Address;
导入android.location.Geocoder;
导入android.location.location;
导入android.os.AsyncTask;
导入android.util.Log;
公共类GeocoderRunner扩展异步任务{
每公里最终静态双长度=0.012682308180089;
每公里最终静态双纬度=0.009;
final static double[]SEARCH_RANGES={1050800,-1};//城市、地区、州、无处不在
私有上下文;
私人地理编码员;
私人位置;
公共地理编码接收器(上下文、位置、,
GeocoderListener地址(LookUpListener){
mContext=上下文;
位置=位置;
mListener=地址lookuplistener;
}
@凌驾
受保护的地址doInBackground(字符串…参数){
Geocoder Geocoder=新的Geocoder(mContext);
列表地址=空;
//参考位置TODO句柄null
双纬度=mLocation.getLatitude();
double lon=mLocation.getLongitude();
int i=0;
试一试{
//循环搜索范围,直到返回地址
做{
//如果范围为-1,则调用getFromLocationName(),而不使用边界框
如果(搜索范围[i]!=-1){
//计算边界框
双lowerLeftLatitude=平移(纬度-搜索范围[i]);
双下经度=平移经度(lon,搜索范围[i]);
双右上纬度=平移(纬度,搜索范围[i]);
双右上经度=平移长度(lon,-搜索范围[i]);
addresses=geocoder.getFromLocationName(参数[0],5,lowerLeftLatitude,lowerLeftLatitude,upperRightLatitude,upperRightLatitude);
}否则{
//万不得已,尝试无限呼叫,结果为20
addresses=geocoder.getFromLocationName(参数[0],20);
}
i++;
}而((addresses==null | | addresses.size()==0)和&i1){
地址最近=空;
收件人(地址:地址){
if(最接近==null)
最近的=地址;
其他的
最近的=获取最近的(mLocation,closest,address);//返回距离mLocation最近的地址
}
返回最近的位置;
}否则
返回地址。获取(0);
}
@凌驾
受保护的void onPostExecute(地址){
如果(地址==null)
mListener.lookupFailed();
其他的
mListener.addressReceived(地址);
}
//侦听器回调
公共接口GeocoderListener{
收到公共无效地址(地址);
public void lookupFailed();
}
//辅助方法
专用静态双translateLat(双lat,双dx){
如果(纬度>0)
返回(纬度+dx*每公里纬度度);
其他的
返回(纬度-dx*每公里纬度度);
}
专用静态双translateLon(双lon,双dy){
如果(lon>0)
返回(lon+dy*每公里lon度);
其他的
返回(lon-dy*lon_DEG_/u KM);
}
私有静态地址getClosest(位置参考,地址address1,地址address2){
double xO=参考getLatitude();
double yO=参考getLongitude();
double x1=address1.getLatitude();
double y1=address1.getLongitude();
double x2=address2.getLatitude();
double y2=address2.getLongitude();
双d1=距离(xO,yO,x1,y1);
双d2=距离(xO,yO,x2,y2);
如果(d1
}


也许这是最好的解决方案,但我想知道是否有一种方法可以在单个调用中实现这一点。

您的代码看起来太复杂了,这里有一种更简单的方法:

    String searchPattern = "123 Main St." 
    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    //I use last known location, but here we can get real location
    Location lastKnownLocation = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

    List<Address> addresses = null;
    try {
        //trying to get all possible addresses by search pattern
        addresses = (new Geocoder(this)).getFromLocationName(searchPattern, Integer.MAX_VALUE);
    } catch (IOException e) {
    }
    if (addresses == null || lastKnownLocation == null) {
        // location service unavailable or incorrect address
        // so returns null
        return null;
    }

    Address closest = null;
    float closestDistance = Float.MAX_VALUE;
    // look for address, closest to our location
    for (Address adr : addresses) {
        if (closest == null) {
            closest = adr;
        } else {
            float[] result = new float[1];
            Location.distanceBetween(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), adr.getLatitude(), adr.getLongitude(), result);
            float distance = result[0];
            if (distance < closestDistance) {
                closest = adr;
                closestDistance = distance;
            }
        }
    }
    return closest; //here can be null if we did not find any addresses by search pattern.
String searchPattern=“123 Main St.”
LocationManager lm=(LocationManager)getSystemService(Context.LOCATION\u服务);
//我使用最后一个已知的位置,但在这里我们可以得到真实的位置
Location lastKnownLocation=lm.getLastKnownLocation(LocationManager.GPS\U提供程序);
列表地址=空;
试一试{
//试图通过搜索模式获取所有可能的地址
    getFromLocationName(String locationName, int maxResults, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude)