9、距离传感器实战:接近检测原理、防误触实现、距离传感器在智能家居中的应用、功耗优化
距离传感器,说白了就是手机顶部那个不起眼的小黑点。你打电话时屏幕自动熄灭,靠的就是它。我最早接触这个传感器是在做一款老人机项目时,那时候才发现,一个小小的距离传感器,坑还真不少。
9.1 接近检测原理
Android 里的距离传感器,大部分是红外方案。发射管发出一束红外光,碰到物体反射回来,接收管收到信号。芯片根据发射和接收的时间差,或者光强衰减,算出距离。
嗯,这里要注意:大多数手机的距离传感器只有「远」和「近」两个状态,不是连续测距。你拿尺子量是量不出精确厘米数的。
核心 API 调用
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
sensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float distance = event.values[0];
// 大部分手机:distance = 0.0 表示贴近,distance = 5.0 表示远离
if (distance < event.sensor.getMaximumRange()) {
// 接近状态
} else {
// 远离状态
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 精度变化,一般不用处理
}
}, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
我个人习惯把 getMaximumRange() 作为阈值。为什么?因为不同厂商的传感器最大范围不一样,有的是 5cm,有的是 8cm。写死 5.0 的话,换台手机就翻车了。
9.2 防误触实现
防误触,这是距离传感器最经典的应用场景。我在项目中遇到过一个问题:用户把手机放口袋里,屏幕被误点亮,结果在口袋里拨出了紧急电话。
解决方案其实不复杂:
- 监听距离传感器状态:当 distance 接近 0 时,标记为「口袋模式」
- 屏蔽触摸事件:在口袋模式下,拦截所有触摸事件
- 退出条件:只有当距离传感器返回「远」状态,且持续 1 秒以上,才退出口袋模式
避坑指南:我曾经在退出条件上只判断了一次「远」状态,结果用户从口袋拿出手机时,手还没离开传感器,屏幕就亮了,又误触了。后来加了个 1 秒的延时,问题解决。
private boolean isInPocket = false;
private long lastFarTime = 0;
@Override
public void onSensorChanged(SensorEvent event) {
float distance = event.values[0];
float maxRange = event.sensor.getMaximumRange();
if (distance < maxRange) {
// 接近 -> 进入口袋模式
isInPocket = true;
lastFarTime = 0;
} else {
// 远离 -> 延迟退出
if (isInPocket) {
if (lastFarTime == 0) {
lastFarTime = System.currentTimeMillis();
} else if (System.currentTimeMillis() - lastFarTime > 1000) {
isInPocket = false;
}
}
}
}
9.3 距离传感器在智能家居中的应用
你以为距离传感器只用在手机上?其实智能家居里用得更多。我参与过一个智能灯控项目,用距离传感器检测人是否在附近,实现人来灯亮、人走灯灭。
典型的应用场景:
| 场景 | 实现方式 | 注意事项 |
|---|---|---|
| 智能灯控 | 检测到人接近 -> 开灯;人离开 -> 延时关灯 | 延时时间要可配置,避免频繁开关 |
| 智能门锁 | 手靠近门把手 -> 唤醒指纹模块 | 功耗要低,否则电池扛不住 |
| 智能水龙头 | 手伸到感应区 -> 出水;手离开 -> 停水 | 响应速度要快,延迟超过 200ms 体验就很差 |
| 智能垃圾桶 | 人靠近 -> 桶盖自动打开 | 要区分人和宠物,不然猫路过盖子就开了 |
你想想看,这些场景本质上都是在做同一件事:用距离传感器判断「有没有人/手在附近」。只是阈值、延时、功耗策略不同而已。
9.4 功耗优化
功耗优化,这是距离传感器开发里最容易被忽视的一环。我见过不少 App,一启动就注册传感器监听,退到后台也不注销,结果电量哗哗地掉。
几个实用的优化策略:
- 按需注册:只在需要的时候注册监听,不需要就注销。比如打电话时注册,挂断后注销。
- 降低采样率:防误触场景不需要高频率,用
SENSOR_DELAY_NORMAL就够了。用SENSOR_DELAY_FASTEST纯属浪费。 - 后台限制:App 进入后台后,如果不需要距离传感器,立即注销。Android 8.0 以后,后台 App 的传感器功耗会被系统限制,但最好还是主动管理。
- 批量处理:如果多个功能都需要距离传感器,合并成一个监听器,不要重复注册。
警告:不要在 onResume() 里注册、onPause() 里注销。因为 Activity 频繁切换时,传感器会反复开关,反而更耗电。建议在 onStart() 和 onStop() 里操作。
@Override
protected void onStart() {
super.onStart();
// 注册传感器
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onStop() {
super.onStop();
// 注销传感器
sensorManager.unregisterListener(this);
}
还有一个细节:距离传感器在大部分手机上,即使不注册监听,系统也会在通话时自动启用。所以如果你只是做防误触,可以依赖系统行为,不用自己再写一套。但如果你需要自定义逻辑(比如游戏防误触),那就得自己来了。
9.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。从传感器原理到应用场景,再到功耗优化,一条线走到底。
距离传感器看起来简单,但要做好,细节不少。从原理到防误触,从智能家居到功耗优化,每一步都有坑。我踩过的坑,希望你别再踩一遍。