You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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;
}

最后总结排查步骤

  1. 先确认你的经纬度坐标系是否统一,是不是都是WGS84;
  2. 检查代码里的方法调用是否正确,有没有拼写错误;
  3. 试试用Haversine公式计算,对比Location类的结果,看是否一致;
  4. 如果是国内地图坐标,先转成WGS84再计算。

内容的提问来源于stack exchange,提问作者user9706969

火山引擎 最新活动