Android中获取两点精确距离失败,求解决方案
搞定经纬度坐标的精确距离计算问题
兄弟,我太懂你试了好几种方法都算不对经纬度距离的崩溃感了!先看看你贴的这段Android Location类的代码,我帮你捋捋可能的问题,再给你几个靠谱的解决方案。
先排查你现有代码的潜在问题
你贴的代码写到startPoint.dista...,应该是打算调用distanceTo(endPoint)吧?这个方法本身是靠谱的,但可能你踩了这几个坑:
- 坐标系不统一:如果你的经纬度是国内地图的GCJ-02(火星坐标)或BD-09(百度坐标),直接用
Location类计算就会有偏差——因为Location默认用的是WGS84国际标准坐标系。 - 方法调用细节:有没有确保调用了正确的方法?
Location类有两个常用的距离计算API:startPoint.distanceTo(endPoint):直接返回两点间的距离,单位是米- 静态方法
Location.distanceBetween(lat1, lon1, lat2, lon2, results):把距离存入results数组的第一个元素
要是你没写完方法名,或者参数传错了,结果肯定不对。
- 浮点数精度不足:如果你的经纬度只保留了4位以下的小数,也会导致计算结果有明显误差,建议至少保留6位小数。
给你补全正确的Location类实现代码
先把你没写完的代码补全,确保调用正确:
private double distance(double lat1, double lon1, double lat2, double lon2) { Location startPoint = new Location("start"); startPoint.setLatitude(lat1); startPoint.setLongitude(lon1); Location endPoint = new Location("end"); endPoint.setLatitude(lat2); endPoint.setLongitude(lon2); // 返回两点间距离,单位:米 return startPoint.distanceTo(endPoint); }
或者用更高效的静态方法:
private double distance(double lat1, double lon1, double lat2, double lon2) { float[] distanceResult = new float[1]; // 结果会存入distanceResult[0],单位:米 Location.distanceBetween(lat1, lon1, lat2, lon2, distanceResult); return distanceResult[0]; }
如果是坐标系问题,先转成WGS84再计算
要是你的经纬度来自国内地图(比如高德、百度),得先把坐标转换成WGS84,再用上面的方法计算。这里给你一个GCJ-02转WGS84的近似实现:
// GCJ-02转WGS84核心方法 private static double[] gcjToWgs(double lat, double lon) { double earthRadius = 6378245.0; double ee = 0.00669342162296594323; double dLat = transformLat(lon - 105.0, lat - 35.0); double dLon = transformLon(lon - 105.0, lat - 35.0); double radLat = lat / 180.0 * Math.PI; double magic = Math.sin(radLat); magic = 1 - ee * magic * magic; double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((earthRadius * (1 - ee)) / (magic * sqrtMagic) * Math.PI); dLon = (dLon * 180.0) / (earthRadius / sqrtMagic * Math.cos(radLat) * Math.PI); return new double[]{lat - dLat, lon - dLon}; } private static double transformLat(double x, double y) { double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; return ret; } private static double transformLon(double x, double y) { double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; return ret; }
使用的时候先转换坐标:
// 假设输入的是GCJ-02坐标 double[] wgsCoords = gcjToWgs(gcjLat, gcjLon); double distance = distance(wgsCoords[0], wgsCoords[1], wgsLat2, wgsLon2);
通用方案:自己实现Haversine公式
如果不想依赖Android的Location类,或者要跨平台使用,直接用经典的Haversine公式实现就行,精度和Location类差不多:
private double haversineDistance(double lat1, double lon1, double lat2, double lon2) { final int EARTH_RADIUS = 6371; // 地球平均半径,单位:公里 double latDiff = Math.toRadians(lat2 - lat1); double lonDiff = Math.toRadians(lon2 - lon1); double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(lonDiff / 2) * Math.sin(lonDiff / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // 转换成米 return EARTH_RADIUS * c * 1000; }
最后总结排查步骤
- 先确认你的经纬度坐标系是否统一,是不是都是WGS84;
- 检查代码里的方法调用是否正确,有没有拼写错误;
- 试试用Haversine公式计算,对比
Location类的结果,看是否一致; - 如果是国内地图坐标,先转成WGS84再计算。
内容的提问来源于stack exchange,提问作者user9706969




