14、位置传感器实战:GPS与网络定位、LocationManager使用、地理围栏实现、位置更新策略

各位同学,今天我们来聊聊位置传感器。说实话,位置服务是Android开发里最常用、也最容易踩坑的功能之一。我自己做过的项目里,十个有八个都跟位置有关——外卖、打车、运动记录,哪个离得开定位?

这一章,我会带大家把位置服务的几个核心点捋清楚:GPS和网络定位怎么选、LocationManager怎么用、地理围栏怎么实现、位置更新策略怎么定。嗯,咱们一个一个来。

14.1 GPS与网络定位:谁更靠谱?

先说说定位方式。Android里主要有两种:GPS定位和网络定位。

GPS定位,说白了就是靠卫星。精度高,能到3-5米,但缺点也明显——室内基本废了,而且首次定位慢,冷启动可能要一两分钟。我在做户外运动App时,就遇到过用户抱怨“打开App半天定不到位”,其实就是GPS冷启动的问题。

网络定位,靠的是基站和Wi-Fi。速度快,室内也能用,但精度嘛...几十米到几百米不等。适合那些不需要精确位置、但需要快速响应的场景,比如天气App、新闻推送。

那怎么选?我个人习惯是:能混用就别单选。Android提供了Criteria类,可以设置精度、功耗等要求,让系统帮你选最合适的Provider。

核心原则:户外高精度用GPS,室内快速响应用网络,两者结合最稳妥。

14.2 LocationManager使用:从入门到实战

LocationManager是Android位置服务的核心API。别看它老,但稳定可靠。我到现在还在用,没出过什么大问题。

先看一个基本的使用流程:

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

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

// 请求位置更新
locationManager.requestLocationUpdates(
    LocationManager.GPS_PROVIDER,  // 使用GPS
    5000,                          // 最小时间间隔:5秒
    10,                            // 最小距离变化:10米
    locationListener               // 回调监听
);

这里有个坑,我曾经踩过:别忘了在Android 6.0以上动态申请权限。位置权限分两种:ACCESS_FINE_LOCATION(精确定位)和ACCESS_COARSE_LOCATION(粗略定位)。如果你只用网络定位,申请粗略权限就够了;如果用GPS,必须申请精确定位权限。

注意:从Android 10开始,后台位置权限需要单独申请,而且Google Play审核非常严格。如果你的App不需要后台定位,千万别申请,否则大概率被拒。

再说说LocationListener。它有几个回调方法,最常用的是onLocationChanged()。但要注意,这个方法在Android 12以后被标记为废弃了,推荐用LocationCallback替代。不过老项目里还是经常见到,大家知道就行。

14.3 地理围栏实现:让App感知“边界”

地理围栏,说白了就是画个圈,用户进圈或出圈时触发事件。比如你走到商场附近,App自动推送优惠券——这就是地理围栏的典型应用。

Android提供了GeofencingClient来实现。我给大家画个流程图,看看整体逻辑:

地理围栏实现流程 1. 定义围栏区域 2. 创建Geofence对象 3. 注册地理围栏 4. 处理进入/退出事件 纬度/经度 半径(米) 过期时间 PendingIntent 触发类型 onEnter/onExit

看明白了吗?流程不复杂,但实现细节要注意。我给大家写个核心代码:

// 1. 定义围栏
Geofence geofence = new Geofence.Builder()
    .setRequestId("fence_001")
    .setCircularRegion(39.9042, 116.4074, 100) // 北京天安门,半径100米
    .setExpirationDuration(Geofence.NEVER_EXPIRE)
    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | 
                        Geofence.GEOFENCE_TRANSITION_EXIT)
    .build();

// 2. 创建请求
GeofencingRequest request = new GeofencingRequest.Builder()
    .addGeofence(geofence)
    .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
    .build();

// 3. 注册
GeofencingClient geofencingClient = LocationServices.getGeofencingClient(this);
geofencingClient.addGeofences(request, getGeofencePendingIntent())
    .addOnSuccessListener(aVoid -> {
        // 注册成功
    })
    .addOnFailureListener(e -> {
        // 注册失败,检查权限和Google Play服务
    });

小技巧:地理围栏的半径不要设太小,建议至少100米。我见过有人设10米,结果用户走半天触发不了——因为GPS精度本身就有波动,太小的围栏根本检测不到。

14.4 位置更新策略:省电与精度的平衡

位置更新策略,说白了就是怎么在省电和精度之间找平衡。这个问题我纠结了很久,后来总结出一套经验。

先看几个关键参数:

参数 说明 建议值
minTime 最小时间间隔(毫秒) 运动类:1000-3000;普通:5000-10000
minDistance 最小距离变化(米) 运动类:5-10;普通:20-50
priority 优先级(高精度/平衡/低功耗) 按场景选择,不要一味追求高精度

我个人习惯的做法是:动态调整策略。比如用户静止时,降低更新频率;用户移动时,提高频率。怎么判断用户是否移动?用ActivityRecognitionClient检测用户状态,然后动态调整LocationRequest的参数。

// 动态调整示例
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(10000); // 默认10秒
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

// 当检测到用户正在步行时,提高精度
if (detectedActivity == DetectedActivity.WALKING) {
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(3000);
}

避坑指南:我曾经在一个运动App里,把minTime设成了1000毫秒,结果用户手机半小时就没电了。后来改成动态策略,续航提升了3倍。记住:能省则省,别让用户骂你“电老虎”

还有一个容易被忽略的点:位置更新的生命周期管理。在Activity或Fragment的onPause()里一定要移除更新,在onResume()里重新请求。否则用户切到后台,你的App还在疯狂定位,等着被系统杀进程吧。

@Override
protected void onPause() {
    super.onPause();
    locationManager.removeUpdates(locationListener);
}

@Override
protected void onResume() {
    super.onResume();
    if (checkLocationPermission()) {
        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 
            5000, 10, locationListener
        );
    }
}

好了,这一章的内容就到这里。位置服务看似简单,但要做好真不容易。从GPS和网络定位的选择,到LocationManager的使用,再到地理围栏和更新策略,每一步都有讲究。希望大家在实际项目中,能把这些知识点用起来,少踩坑、多省电。


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