安卓定位代码参数解析与调整

解析 locationManager.requestLocationUpdates() 方法

这段代码是Android中用于请求位置更新的方法调用。我来详细解释它的含义和可调整参数:

方法解释

locationManager.requestLocationUpdates(
    LocationManager.GPS_PROVIDER, // 位置提供者
    0,                           // 最小时间间隔(毫秒)
    0,                           // 最小距离间隔(米)
    locationListener             // 位置监听器
);

这个方法告诉系统你想要定期接收位置更新,当位置发生变化时会通过locationListener回调通知你。

参数详解及可调整变量

  1. 位置提供者 (provider):

    • LocationManager.GPS_PROVIDER - 使用GPS卫星定位,精度高但耗电,需要户外
    • LocationManager.NETWORK_PROVIDER - 使用网络定位(WiFi/基站),精度较低但室内可用
    • LocationManager.PASSIVE_PROVIDER - 被动接收其他应用请求的位置更新
  2. 最小时间间隔 (minTime, 毫秒):

    • 这里设置为0表示尽可能快地获取更新
    • 可以调整为更大的值以减少耗电,例如5000表示至少5秒更新一次
    • 实际更新时间可能比这个长,但不会比它短
  3. 最小距离间隔 (minDistance, 米):

    • 这里设置为0表示位置有任何变化都通知
    • 可以设置为例如10,表示移动超过10米才通知
    • 有助于减少不必要的回调
  4. 位置监听器 (listener):

    • 需要实现LocationListener接口
    • 接收四个回调方法:
      • onLocationChanged(Location location) - 位置更新时调用
      • onStatusChanged(String provider, int status, Bundle extras)
      • onProviderEnabled(String provider)
      • onProviderDisabled(String provider)

使用建议

  1. 为了平衡精度和电池消耗,可以考虑:

    // 每5秒或移动10米以上时更新
    locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        5000,
        10,
        locationListener);
    
  2. 在Android 6.0+上需要先请求位置权限:

    • ACCESS_FINE_LOCATION (GPS)
    • ACCESS_COARSE_LOCATION (网络)
  3. 不再需要更新时,记得调用:

    locationManager.removeUpdates(locationListener);
    
  4. 对于现代Android开发,推荐使用Fused Location Provider (Google Play Services)代替直接使用LocationManager,它能更智能地管理电量和精度平衡。

位置提供者 (provider)可以混合使用吗

位置提供者(provider)可以混合使用吗?

在Android定位系统中,位置提供者是可以混合使用的,但需要注意一些实现细节和最佳实践。

混合使用位置提供者的方式

  1. 同时注册多个提供者
    你可以为同一个LocationListener注册多个提供者:

    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, listener);
    locationManager.requestUpdates(LocationManager.NETWORK_PROVIDER, minTime, minDistance, listener);
    
  2. 不同监听器处理不同提供者

    // GPS监听器
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, gpsListener);
    
    // 网络监听器
    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, minTime, minDistance, networkListener);
    

混合使用的注意事项

  1. 回调顺序不确定

    • 你无法预知哪个提供者会先返回位置
    • 同一个监听器可能收到来自不同提供者的回调
  2. 精度处理

    • GPS通常比网络定位更精确
    • 可以在onLocationChanged()中比较位置精度,选择使用更精确的结果
  3. 电量消耗

    • 同时使用多个提供者会增加电量消耗
    • 特别是GPS和网络同时激活时
  4. 现代替代方案

    • 推荐使用FusedLocationProviderClient(Google Play Services的一部分)
    • 它会自动选择最佳提供者并优化电量使用

示例代码:混合使用并选择最佳位置

LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        // 比较新位置和之前保存的位置,选择更精确的
        if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) {
            bestLocation = location;
            // 使用最佳位置更新UI或进行其他操作
        }
    }
    // ...其他回调方法
};

// 注册两个提供者
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 50, locationListener);

最佳实践建议

  1. 根据场景选择

    • 户外导航:优先使用GPS
    • 室内定位:使用网络定位
    • 快速获取初始位置:先网络后GPS
  2. 超时切换机制

    • 如果GPS长时间无法定位,可以切换到网络定位
  3. 权限管理

    • 同时需要ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION权限
  4. 电量优化

    • 获取到足够精确的位置后,减少更新频率或停止不必要的提供者

对于大多数现代应用,Google推荐的Fused Location Provider已经内置了这些优化策略,通常是更好的选择。

返回的位置是什么坐标系

Android 定位返回的坐标系

Android 定位系统返回的位置坐标使用的是 WGS84 坐标系(World Geodetic System 1984),这是全球通用的 GPS 标准坐标系。

坐标系详情

  1. WGS84 坐标系特点

    • 经度 (Longitude):-180 到 180 度,东经为正,西经为负
    • 纬度 (Latitude):-90 到 90 度,北纬为正,南纬为负
    • 海拔高度 (Altitude):相对于 WGS84 椭球面的高度,单位米
  2. Location 对象中的坐标数据

    Location location; // 从onLocationChanged获取的位置对象
    double latitude = location.getLatitude();  // 纬度
    double longitude = location.getLongitude(); // 经度
    double altitude = location.getAltitude();   // 海拔(可能有值也可能为0)
    float accuracy = location.getAccuracy();    // 水平精度半径(米)
    

其他坐标系转换

如果需要使用其他坐标系(如中国常用的GCJ-02或BD-09),需要自行转换:

  1. 中国特有坐标系

    • GCJ-02(火星坐标系):中国官方对WGS84加密后的坐标系
    • BD-09:百度在GCJ-02基础上二次加密的坐标系
  2. 转换方法

    // WGS84转GCJ-02示例
    public static native double[] wgs84ToGcj02(double wgsLat, double wgsLon);
    
    // GCJ-02转BD-09示例
    public static native double[] gcj02ToBd09(double gcjLat, double gcjLon);
    

    (实际实现需要引入相应的算法库或使用第三方SDK)

谷歌地图是WGS-84坐标系,但在国内是使用GCJ-02坐标系。

百度地图是在使用GCJ-02 加密的基础上,又通过自己的加密算法BD-09 又对坐标进行了二次加密。

我国要求,每一个地图产品都要使用“ GCJ-02 ” 进行首次加密,不能直接使用原始坐标体系。高德、腾讯等都是用的这个坐标系。

重要注意事项

  1. 中国大陆地区特殊要求

    • 在中国大陆,所有公开地图API返回的坐标都必须是GCJ-02坐标系
    • 直接使用原始GPS坐标(WGS84)在地图上会有偏移
  2. 精度信息

    • location.getAccuracy()返回的是以米为单位的水平精度半径
    • 值越小表示精度越高(GPS通常1-20米,网络定位通常20-500米)
  3. 时间戳

    • location.getTime()返回UTC时间戳(毫秒),可通过new Date(location.getTime())转换
  4. 速度信息(如果有):

    • location.getSpeed() 米/秒
    • location.getBearing() 方向角度(相对于正北)

如果您需要在中国地图上显示位置,必须将WGS84坐标转换为GCJ-02或BD-09坐标系,否则会出现位置偏移问题。

在安卓开发中(java),如何将WGS84坐标转换为BD-09坐标系?

在Android Java中将WGS84坐标转换为BD-09坐标系

在中国地图应用开发中,由于坐标加密系统的存在,需要将GPS获取的WGS84坐标先转换为GCJ-02(火星坐标),再转换为BD-09(百度坐标)才能正确显示在百度地图上。

完整转换实现

以下是一个完整的Java实现,包含WGS84→GCJ-02和GCJ-02→BD-09的转换:

public class CoordinateConverter {
    private static final double x_PI = 3.14159265358979324 * 3000.0 / 180.0;
    private static final double PI = 3.1415926535897932384626;
    private static final double a = 6378245.0;
    private static final double ee = 0.00669342162296594323;

    /**
     * WGS84转GCJ02(火星坐标系)
     */
    public static double[] wgs84ToGcj02(double lng, double lat) {
        if (outOfChina(lng, lat)) {
            return new double[]{lng, lat};
        }
        double dlat = transformLat(lng - 105.0, lat - 35.0);
        double dlng = transformLng(lng - 105.0, lat - 35.0);
        double radlat = lat / 180.0 * PI;
        double magic = Math.sin(radlat);
        magic = 1 - ee * magic * magic;
        double sqrtmagic = Math.sqrt(magic);
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
        double mglat = lat + dlat;
        double mglng = lng + dlng;
        return new double[]{mglng, mglat};
    }

    /**
     * GCJ02转BD09(百度坐标系)
     */
    public static double[] gcj02ToBd09(double lng, double lat) {
        double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
        double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
        double bd_lng = z * Math.cos(theta) + 0.0065;
        double bd_lat = z * Math.sin(theta) + 0.006;
        return new double[]{bd_lng, bd_lat};
    }

    /**
     * WGS84转BD09(百度坐标系) - 两步转换
     */
    public static double[] wgs84ToBd09(double lng, double lat) {
        double[] gcj02 = wgs84ToGcj02(lng, lat);
        return gcj02ToBd09(gcj02[0], gcj02[1]);
    }

    private static boolean outOfChina(double lng, double lat) {
        return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
    }

    private static double transformLat(double lng, double lat) {
        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    private static double transformLng(double lng, double lat) {
        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }
}

使用示例

// 从Location获取WGS84坐标
Location location = ...; // 从GPS获取的位置
double wgsLng = location.getLongitude();
double wgsLat = location.getLatitude();

// 转换为BD-09坐标系
double[] bd09 = CoordinateConverter.wgs84ToBd09(wgsLng, wgsLat);
double bdLng = bd09[0];
double bdLat = bd09[1];

Log.d("Coordinate", "原始坐标(WGS84): " + wgsLng + "," + wgsLat);
Log.d("Coordinate", "百度坐标(BD09): " + bdLng + "," + bdLat);

注意事项

  1. 中国大陆地区才需要转换outOfChina方法会判断坐标是否在中国境内,境外坐标不需要转换
  2. 精度问题:转换算法有一定精度误差,通常在实际应用中可忽略
  3. 百度地图SDK:如果使用百度地图SDK,它提供了内置的坐标转换方法
    // 使用百度地图SDK的转换方法
    LatLng sourceLatLng = new LatLng(wgsLat, wgsLng);
    LatLng desLatLng = CoordinateConverter.convert(sourceLatLng, 
        CoordType.GPS); // GPS即WGS84
    
  4. 性能考虑:频繁转换可能影响性能,建议在需要显示时再转换

其他方案

  1. 使用百度地图Web API

    // 调用百度地图坐标转换API(需要网络)
    String url = "http://api.map.baidu.com/geoconv/v1/?coords=" + lng + "," + lat + 
        "&from=1&to=5&ak=您的AK";
    
  2. 使用第三方库:如coordtransform等开源库

以上实现可以满足大多数Android应用中WGS84到BD-09坐标转换的需求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容