如何通过系统运动状态回调启停传感器数据采集的前台服务
需求:手机非静止状态下采集加速度计、陀螺仪传感器数据
已实现功能
- 使用 Sensor Listener 监听传感器数据
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager val accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) sensorManager.registerListener( accSensor, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL )
- 运行前台服务在后台持续跟踪传感器数据,应用从最近任务列表划走也可正常运行
serviceIntent = Intent(context, SensorService::class.java) context.startForegroundService(serviceIntent)
- 通过监听开机完成事件的广播接收器,实现设备重启后自动启动服务
未解决问题
- 无法在设备停止移动时停止采集传感器数据的服务
- 无法在用户设备开始移动时启动未运行的传感器完成数据采集
实现方案
Android 系统本身提供了低功耗的显著运动检测能力,配合自定义的静止判断逻辑,即可实现根据设备运动状态自动启停采集服务:
1. 运动开始检测
使用系统内置的 *Sensor.TYPE_SIGNIFICANT_MOTION* 传感器,该传感器由硬件层实现,功耗极低,仅在检测到设备发生显著位移(如用户拿起手机、步行移动)时触发回调,非常适合作为运动启动的触发信号。
注册代码示例:
// 检查设备是否支持显著运动检测 val significantMotionSensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION) if (significantMotionSensor != null) { val motionTriggerListener = object : TriggerEventListener() { override fun onTrigger(event: TriggerEvent?) { // 检测到运动启动,启动前台采集服务 if (!isServiceRunning(SensorService::class.java)) { val serviceIntent = Intent(context, SensorService::class.java) context.startForegroundService(serviceIntent) } // 单次触发后需重新注册才能检测下一次运动 sensorManager.requestTriggerSensor(this, significantMotionSensor) } } // 注册触发器 sensorManager.requestTriggerSensor(motionTriggerListener, significantMotionSensor) } else { // 设备不支持硬件显著运动检测,降级使用低采样率加速度计轮询判断运动 }
注意:Android 10及以上系统需要申请 ACTIVITY_RECOGNITION 权限才能正常使用该传感器。
2. 运动结束检测
系统没有提供标准的运动结束回调,可在采集服务运行期间,通过加速度计数值判断设备是否持续静止,达到阈值后自动停止服务:
判断逻辑:计算三轴加速度的合值,减去重力加速度(9.81m/s²)得到运动产生的加速度,如果该值持续3~5秒低于设定的静止阈值,即可判定设备停止运动,停止采集服务。
代码示例:
private var lastMovingTime = System.currentTimeMillis() // 静止阈值,可根据业务需求调整,避免微小晃动误判 private val STATIONARY_THRESHOLD = 0.2f // 持续静止3秒触发服务停止 private val STOP_DELAY = 3000L val accSensor = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent?) { event ?: return val x = event.values[0] val y = event.values[1] val z = event.values[2] // 计算合加速度 val totalAcc = sqrt(x*x + y*y + z*z) // 扣除重力影响,得到仅由运动产生的加速度 val motionAcc = abs(totalAcc - 9.81f) if (motionAcc > STATIONARY_THRESHOLD) { lastMovingTime = System.currentTimeMillis() // 原有传感器数据采集逻辑 saveSensorData(event.values) } else { // 静止时长达到阈值,停止服务 if (System.currentTimeMillis() - lastMovingTime > STOP_DELAY) { stopForeground(STOP_FOREGROUND_REMOVE) stopSelf() } } } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) = Unit }
内容的提问来源于stack exchange,提问作者erluxman
相关产品推荐
相关产品推荐

