一、初识定位:Android定位技术概览、GPS与网络定位原理、LocationManager入门

大家好,我是你们的老朋友。今天咱们正式开启Android定位之旅。

说实话,定位功能在移动开发里太常见了。外卖、打车、导航、打卡……哪个App离得开位置?我当年刚接触Android时,第一个让我觉得“哇,手机真智能”的功能就是定位。你想想看,手机怎么知道你在哪?这背后其实是一套挺精巧的技术组合。

1.1 定位技术概览:手机是怎么知道你在哪的?

Android系统支持多种定位方式。说白了,就是“八仙过海,各显神通”。每种方式都有自己的脾气秉性。

  • GPS定位:精度最高,但耗电也最猛。室外空旷处能到3-5米。
  • 网络定位:包括Wi-Fi和基站定位。速度快,室内也能用,但精度差一些。
  • 被动定位:不主动请求位置,而是监听其他App或系统发来的位置更新。省电,但不可控。

我个人习惯把定位技术分成两类:卫星定位地面定位。卫星定位就是GPS、北斗这些;地面定位就是Wi-Fi、基站、蓝牙信标等。两者各有优劣,实际项目中往往是混合使用。

核心要点:没有一种定位方式是完美的。GPS在室内几乎废掉,网络定位在郊区可能偏差几百米。所以Android提供了LocationProvider机制,让开发者根据场景选择或组合使用。

1.2 GPS定位原理:天上的星星不说话?不,它们一直在说话

GPS的原理其实不复杂。24颗卫星绕着地球飞,每颗卫星都在不停地广播自己的位置和时间。你的手机收到至少4颗卫星的信号,就能算出自己的经纬度和海拔。

嗯,这里要注意:GPS信号很弱,穿透力差。我在项目中遇到过,用户把手机放在裤子口袋里,在室内靠窗的位置,定位就断断续续的。更别说地下车库了——直接歇菜。

小技巧:GPS首次定位需要下载星历数据,这叫“冷启动”。如果App需要快速定位,可以先用网络定位拿到粗略位置,同时让GPS在后台搜星。等GPS精度上来了,再切换过去。这个策略我用了好多年,效果不错。

1.3 网络定位原理:Wi-Fi和基站是怎么定位的?

网络定位的原理,说白了就是“查表”。

Google维护着一个巨大的数据库,里面记录了全球Wi-Fi热点的MAC地址和基站ID对应的地理位置。你的手机扫描到周围的Wi-Fi或基站,把信息发到服务器,服务器返回一个估算位置。

你想想看,这玩意精度能有多高?在城市里,Wi-Fi密集的地方,能到20-50米。到了郊区,基站间距几公里,那误差就大了去了。

我曾经在一个物流项目中踩过坑:用户在农村仓库里签收货物,网络定位直接偏了300米,导致系统判定“不在配送范围”。后来我们加了GPS兜底,才解决这个问题。

避坑指南:网络定位依赖Google Play服务。如果你的App要出海,没问题。但如果只在国内用,很多国产手机阉割了Google服务,网络定位会失效。这时候你得用各家厂商的定位SDK,或者用高德、百度地图的定位组件。

1.4 LocationManager入门:Android定位的“老司机”

LocationManager是Android最早提供的定位API。虽然现在Google推荐用FusedLocationProviderClient,但理解LocationManager仍然很重要——它是地基。

使用LocationManager分三步走:

  1. 获取系统服务:getSystemService(Context.LOCATION_SERVICE)
  2. 选择定位Provider:GPS_PROVIDER或NETWORK_PROVIDER
  3. 注册位置监听器:requestLocationUpdates()

来看一段最基础的代码:

// 获取LocationManager
LocationManager locationManager = 
    (LocationManager) getSystemService(Context.LOCATION_SERVICE);

// 检查GPS是否可用
boolean isGpsEnabled = locationManager.isProviderEnabled(
    LocationManager.GPS_PROVIDER);

if (isGpsEnabled) {
    // 请求位置更新,最小时间间隔1000ms,最小距离变化1米
    locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        1000,   // 最小时间间隔(毫秒)
        1f,     // 最小距离变化(米)
        new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                // 拿到位置了!
                double lat = location.getLatitude();
                double lng = location.getLongitude();
                Log.d("Location", "纬度:" + lat + ",经度:" + lng);
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
                // 定位状态变化,比如GPS信号丢失
            }

            @Override
            public void onProviderEnabled(String provider) {
                // 定位开关被打开
            }

            @Override
            public void onProviderDisabled(String provider) {
                // 定位开关被关闭
            }
        },
        Looper.getMainLooper()  // 回调在主线程执行
    );
}

注意requestLocationUpdates()的第一个参数是定位Provider。你可以传LocationManager.GPS_PROVIDERLocationManager.NETWORK_PROVIDER。也可以传LocationManager.PASSIVE_PROVIDER,但那个比较特殊,后面章节再细聊。

这段代码跑起来,你的App就能收到位置更新了。但别高兴太早——有几个坑等着你。

第一,权限问题。Android 6.0以上需要动态申请ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION权限。忘了申请?直接闪退,没商量。

第二,主线程问题。上面的代码把回调放在主线程,如果你的onLocationChanged()里做了耗时操作,UI会卡顿。我建议在子线程处理位置数据,或者用Handler做线程切换。

第三,耗电问题。GPS一直开着,电量哗哗地掉。记得在不需要定位时调用removeUpdates()

我的习惯:在onPause()里移除位置更新,在onResume()里重新注册。这样用户切到后台时,定位就停了,省电又省心。

1.5 本章知识体系:一张图看懂定位技术

下面这张SVG图,把本章的核心知识点串起来了。你可以把它当作一张“定位技术地图”。

Android定位技术概览 GPS定位 网络定位 被动定位 原理 24颗卫星广播位置和时间 手机接收信号计算经纬度 精度:3-5米(室外) 原理 扫描Wi-Fi/基站MAC地址 查询服务器数据库 精度:20-300米 原理 监听其他App的位置更新 不主动请求定位 最省电,但不可控 LocationManager 统一管理 核心API:getSystemService() → requestLocationUpdates() → onLocationChanged() 注意:Android 6.0+ 需要动态申请定位权限

1.6 本章小结

这一章我们聊了定位技术的三大流派:GPS、网络定位和被动定位。也上手写了第一段LocationManager代码。

说实话,LocationManager虽然老,但它是理解Android定位机制的基石。你把它搞明白了,后面学FusedLocationProviderClient会轻松很多。

嗯,最后提醒一句:定位权限一定要动态申请。我见过太多新手在真机上跑定位Demo,结果闪退,然后一脸懵逼地问我“代码没问题啊”。其实问题就出在权限上。

好了,这一章就到这里。下一章我们深入聊聊定位权限的那些坑——怎么申请、怎么兼容、怎么处理用户拒绝。到时候见。


公众号:蓝海资料掘金营,微信deep3321