一、初识定位: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分三步走:
- 获取系统服务:
getSystemService(Context.LOCATION_SERVICE) - 选择定位Provider:GPS_PROVIDER或NETWORK_PROVIDER
- 注册位置监听器:
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_PROVIDER或LocationManager.NETWORK_PROVIDER。也可以传LocationManager.PASSIVE_PROVIDER,但那个比较特殊,后面章节再细聊。
这段代码跑起来,你的App就能收到位置更新了。但别高兴太早——有几个坑等着你。
第一,权限问题。Android 6.0以上需要动态申请ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限。忘了申请?直接闪退,没商量。
第二,主线程问题。上面的代码把回调放在主线程,如果你的onLocationChanged()里做了耗时操作,UI会卡顿。我建议在子线程处理位置数据,或者用Handler做线程切换。
第三,耗电问题。GPS一直开着,电量哗哗地掉。记得在不需要定位时调用removeUpdates()。
我的习惯:在onPause()里移除位置更新,在onResume()里重新注册。这样用户切到后台时,定位就停了,省电又省心。
1.5 本章知识体系:一张图看懂定位技术
下面这张SVG图,把本章的核心知识点串起来了。你可以把它当作一张“定位技术地图”。
1.6 本章小结
这一章我们聊了定位技术的三大流派:GPS、网络定位和被动定位。也上手写了第一段LocationManager代码。
说实话,LocationManager虽然老,但它是理解Android定位机制的基石。你把它搞明白了,后面学FusedLocationProviderClient会轻松很多。
嗯,最后提醒一句:定位权限一定要动态申请。我见过太多新手在真机上跑定位Demo,结果闪退,然后一脸懵逼地问我“代码没问题啊”。其实问题就出在权限上。
好了,这一章就到这里。下一章我们深入聊聊定位权限的那些坑——怎么申请、怎么兼容、怎么处理用户拒绝。到时候见。