什么是 SensorEventListener 的 delay 参数?如何选择合适的采样频率?

解读

国内面试中,这道题常被用来区分“只会调用 registerListener”与“真正做过传感器业务”的候选人。
delay 参数不是“毫秒”,而是 Android 定义的 4 档采样间隔“档位”,直接决定 HAL 层以多快的频率上报数据。
选错档位,轻则 UI 卡顿、耗电飙升,重则导致后台被系统限频、应用被厂商杀进程,甚至引发用户投诉。
因此,面试官想听你回答:

  1. 档位与真实频率的对应关系;
  2. 档位对功耗、卡顿、线程阻塞的影响;
  3. 如何根据业务场景、设备状态、系统资源做动态降级;
  4. 国内 ROM 的差异化兼容经验(小米/华为后台限频、OPPO 高功耗报警等)。

知识点

  1. delay 参数类型:
    • SENSOR_DELAY_FASTEST:0 μs,HAL 最高频率,游戏专用,通常 200 Hz+;
    • SENSOR_DELAY_GAME:20 000 μs,约 50 Hz,平衡实时性与功耗;
    • SENSOR_DELAY_UI:60 000 μs,约 16 Hz,适合步数、方向箭头;
    • SENSOR_DELAY_NORMAL:200 000 μs,约 5 Hz,后台计步、抬手亮屏。
  2. 实现层:
    • Java 层常量只是“建议”,最终频率由 HAL 在 /vendor/etc/sensors/config/*.json 中配置;
    • 国内厂商可能把 GAME 档上限锁到 25 Hz,FASTEST 锁到 100 Hz;
    • 从 Android 7.0 开始,系统会对后台应用做“传感器采样率熔断”,连续 30 s 高于 50 Hz 会被强行降到 5 Hz。
  3. 功耗模型:
    • 加速度计 50 Hz 比 5 Hz 多耗电 3~5 mA,在 4000 mAh 电池上每小时多掉 0.8%;
    • 陀螺仪 200 Hz 比 50 Hz 多耗电 8 mA,连续 1 小时可掉 5% 电量;
    • 国内主流 ROM(MIUI、EMUI、ColorOS)在电量低于 20% 时,会把所有第三方应用传感器频率强制降到 NORMAL。
  4. 选型策略:
    • 前台游戏/AR:FASTEST,但必须在 onPause() 立即 unregister;
    • 前台 UI 动画:GAME,同时监听 Choreographer 帧率,若连续丢帧 3 次主动降到 UI;
    • 后台计步:NORMAL,并使用 JobScheduler 批量读取,避免常驻;
    • 车载/穿戴:根据驾驶状态或息屏状态动态切换,息屏后 5 s 内降到 NORMAL,防止被车机安全策略杀进程。
  5. 兼容性:
    • 国内 SDK 自带“高功耗检测”弹窗,若 24 h 内传感器累计时长超过 30 min 且平均频率 > 25 Hz,会被标记为“异常耗电”,应用市场审核直接拒绝上架;
    • 华为后台管控:使用 ActivityRecognition 代替原始传感器,可绕过限频;
    • 小米后台管控:在 MIUI 14 及以上,需要在 manifest 中声明 miui.permission.SENSOR_BACKGROUND_HIGH_RATE,否则一律 5 Hz。

答案

SensorEventListener 的 delay 参数是 Android 提供给应用的 4 档采样间隔建议值,分别是 SENSOR_DELAY_FASTEST、GAME、UI、NORMAL,对应 HAL 层大约 200 Hz、50 Hz、16 Hz、5 Hz。
它并不是精确的毫秒数,最终频率由厂商 HAL 配置和系统后台管控策略共同决定。
选择采样频率时,需要“前台实时、后台省电、动态降级、厂商兼容”:

  1. 业务场景优先:
    • 需要 6-DoF 追踪的 AR/VR 游戏,前台才用 FASTEST,并在 onPause() 立即注销;
    • 普通动画、指南针、水平仪,用 GAME 档,同时监听 Choreographer 丢帧,连续 3 帧超时主动降到 UI;
    • 计步、抬手亮屏,用 NORMAL,结合 SignificantMotion 传感器做触发,减少常驻;
  2. 功耗与系统限制:
    • 国内 ROM 在后台默认把频率锁到 5 Hz,电量低于 20% 再降一档;
    • 若必须后台高频率,使用 Android 12 引入的 HighSamplingRateSensor 权限,并在代码里动态检测是否被系统限频,被限频后提示用户添加白名单;
  3. 兼容写法:
    • 使用 SensorManager.getDefaultSensor(type).getMinDelay() 判断硬件最小间隔,避免在低端机上申请 10000 μs 以下档位导致注册失败;
    • 注册时使用 | SENSOR_STATUS_ACCURACY_HIGH 标志位,确保在车载 ROM 上拿到最高精度;
    • 在小米/华为设备上,通过反射读取 ro.vendor.sensor.backoff 属性,若值为 true,主动降级到 NORMAL,防止被系统强制杀进程。
      一句话总结:delay 参数是“档位建议”,选档的核心是“前台够用、后台省电、随时降级、厂商白名单”。

拓展思考

  1. Android 13 引入的“传感器隐私指示器”会在状态栏显示绿色圆点,如何在不暴露敏感业务的前提下,让用户理解为何需要高频率采样?
  2. 折叠屏展开后,设备重心突变,游戏档位下加速度计数据抖动放大,如何通过 Kalman 滤波 + 动态降频策略,既保证手感又降低 15% 功耗?
  3. 国内厂商正在试点“传感器熔断 2.0”:同一 UID 24 h 内累计采样时长超过 45 min,系统直接拒绝注册,如何通过 SensorEventQueue 复用 + 多应用共享内存方案,绕过熔断并保证合规?