19、触发传感器事件:使用 triggerSensor 实现单次触发
各位同学,今天我们来聊一个很有意思的话题——单次触发。
前面我们一直在用 registerListener 监听传感器,那是持续不断的。但有些场景下,你只需要传感器响应一次。比如:
- 摇一摇手机触发某个动作
- 翻转手机静音
- 拍一下手机亮屏
这种「一次就好」的需求,用 triggerSensor 再合适不过了。
什么是 triggerSensor?
triggerSensor 是 Android 提供的一个一次性传感器触发机制。你调用它,传感器就工作一次,返回数据后自动停止。说白了,就是「用完即走」,不占资源。
我个人习惯把它比作「按门铃」——你按一下,门铃响一声,完事。而 registerListener 就像一直开着门,谁路过都响一下。
哪些传感器支持单次触发?
不是所有传感器都支持 triggerSensor。目前主要支持的是:
| 传感器类型 | 说明 |
|---|---|
TYPE_SIGNIFICANT_MOTION |
检测到显著移动时触发一次 |
TYPE_STEP_DETECTOR |
每走一步触发一次 |
TYPE_TILT_DETECTOR |
检测到倾斜时触发一次 |
嗯,这里要注意:陀螺仪本身不支持单次触发。但我们可以用陀螺仪数据配合 triggerSensor 的思路,自己实现类似效果。这个后面会讲。
核心 API:TriggerEventListener
使用 triggerSensor 需要两个关键对象:
SensorManager—— 传感器管理器TriggerEventListener—— 一次性监听器
代码结构其实很简单:
// 1. 获取传感器管理器
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
// 2. 获取传感器实例
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
// 3. 创建一次性监听器
TriggerEventListener listener = new TriggerEventListener() {
@Override
public void onTrigger(TriggerEvent event) {
// 这里只执行一次
float timestamp = event.timestamp;
boolean triggered = event.values[0] == 1.0f;
if (triggered) {
Log.d("SensorDemo", "检测到显著移动!时间戳:" + timestamp);
}
}
};
// 4. 注册单次触发
sensorManager.requestTriggerSensor(listener, sensor);
看到没?没有 onAccuracyChanged,没有 onSensorChanged 的持续回调。就一个 onTrigger,触发完就结束。
关键区别:
registerListener→ 持续监听,需要手动unregisterrequestTriggerSensor→ 触发一次,自动注销
实战:用陀螺仪实现「摇一摇单次触发」
虽然陀螺仪没有原生单次触发,但我们可以自己封装。我在项目中就遇到过这种需求——用户摇一下手机切换歌曲,但不能一直摇,摇一次就停。
思路是这样的:
- 用
registerListener监听陀螺仪 - 检测到角速度超过阈值时,执行一次动作
- 立即注销监听器,实现「单次」效果
代码实现:
public class ShakeOnceDetector {
private SensorManager sensorManager;
private Sensor gyroscope;
private SensorEventListener listener;
private static final float SHAKE_THRESHOLD = 3.0f; // 弧度/秒
public void startSingleShakeDetection() {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
listener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
double magnitude = Math.sqrt(x*x + y*y + z*z);
if (magnitude > SHAKE_THRESHOLD) {
// 检测到摇动,执行动作
onShakeDetected();
// 关键:立即注销,实现单次触发
sensorManager.unregisterListener(this);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 不需要处理
}
};
sensorManager.registerListener(listener, gyroscope,
SensorManager.SENSOR_DELAY_FASTEST);
}
private void onShakeDetected() {
Log.d("ShakeOnce", "摇动检测完成!已自动停止监听。");
// 这里放你的业务逻辑
}
}
小技巧:如果你想让用户再次触发,可以提供一个 reset() 方法,重新调用 registerListener。这样既实现了「单次」,又保留了「可重复」的能力。
避坑指南
我曾经踩过一个坑:用 triggerSensor 监听 TYPE_SIGNIFICANT_MOTION,结果在模拟器上怎么都触发不了。后来才发现,这个传感器需要真实的硬件支持,模拟器基本不模拟。
还有一点:单次触发不等于低功耗。虽然它只触发一次,但触发前的监听过程仍然会消耗电量。别指望用它来省电,省的是你的代码复杂度。
注意事项:
triggerSensor不支持所有传感器,使用前先检查sensor.isTriggerSensor()- 触发后监听器自动注销,不需要手动
unregister - 如果传感器不支持,
requestTriggerSensor会返回 false - 在 Android 4.4+ 才支持
TriggerEventListener
核心逻辑流程图
下面这张图帮你理清 triggerSensor 和自实现单次触发的区别:
总结一下
triggerSensor 是个好东西,但适用范围有限。对于陀螺仪这种不支持原生单次触发的传感器,我们完全可以自己动手封装。你想想看,核心就三步:监听 → 判断 → 注销。
我个人建议:如果你的传感器支持原生单次触发,优先用 triggerSensor。如果不支持,就用我上面那个「摇一摇」的模板,改改阈值就能用。
嗯,今天就到这里。代码不多,但思路很重要。下次你遇到「只触发一次」的需求,应该知道怎么做了吧?
公众号:蓝海资料掘金营,微信deep3321