Android Kotlin实现每分钟向REST API发送传感器与心率数据
解决方案
一、解决屏幕熄灭后传感器数据停止的问题
Android屏幕熄灭后会进入低功耗模式,后台服务易被系统限制,需做以下调整:
- 使用前台服务(Foreground Service):前台服务会在通知栏保留持续通知,系统不会轻易终止它。在服务启动时调用
startForeground():
// 先创建通知渠道(Android 8.0+必填) private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel(CHANNEL_ID, "数据采集通道", NotificationManager.IMPORTANCE_LOW) val manager = getSystemService(NotificationManager::class.java) manager.createNotificationChannel(channel) } } // 在服务onCreate/onStartCommand中启动前台服务 override fun onCreate() { super.onCreate() createNotificationChannel() val notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("数据采集服务") .setContentText("正在采集运动与心率数据") .setSmallIcon(R.drawable.ic_notification) .build() startForeground(NOTIFICATION_ID, notification) }
- 申请唤醒锁(Wake Lock):保证屏幕熄灭后CPU仍能运行,记得在不需要时释放避免耗电:
private lateinit var wakeLock: PowerManager.WakeLock override fun onCreate() { super.onCreate() val powerManager = getSystemService(POWER_SERVICE) as PowerManager wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::DataLock") wakeLock.acquire(60*1000L /* 可设置超时时间,按需调整 */) } override fun onDestroy() { super.onDestroy() if (wakeLock.isHeld) wakeLock.release() }
同时在Manifest中添加权限:<uses-permission android:name="android.permission.WAKE_LOCK" />
- Android 12+需额外申请
POST_NOTIFICATIONS权限,否则前台服务无法启动。
二、将MeasureClient整合到服务中
直接在服务内初始化MeasureClient并管理其生命周期,同步两类数据后定时上报:
- 服务内初始化MeasureClient:
private lateinit var measureClient: MeasureClient private var latestHeartRate: Int? = null override fun onCreate() { super.onCreate() measureClient = MeasureClient(this) // 请求健康数据权限并启动监听 measureClient.requestPermissions { granted -> if (granted) startHeartRateListen() } } private fun startHeartRateListen() { measureClient.registerHeartRateCallback { rate -> latestHeartRate = rate } }
- 同步加速度与心率数据,定时上报:
在服务中维护最新的加速度数据,用定时器每分钟触发一次API请求:
private var latestAccelData: FloatArray? = null private val uploadHandler = Handler(Looper.getMainLooper()) private val uploadTask = object : Runnable { override fun run() { // 两类数据都存在时才上报 latestAccelData?.let { accel -> latestHeartRate?.let { rate -> sendCombinedDataToApi(accel, rate) } } uploadHandler.postDelayed(this, 60 * 1000) } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { uploadHandler.post(uploadTask) // 初始化加速度传感器监听 initAccelerometer() return START_STICKY } private fun initAccelerometer() { val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager val accelSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) sensorManager.registerListener(this, accelSensor, SensorManager.SENSOR_DELAY_NORMAL) } // 实现SensorEventListener的onSensorChanged更新加速度数据 override fun onSensorChanged(event: SensorEvent?) { event?.takeIf { it.sensor.type == Sensor.TYPE_ACCELEROMETER }?.let { latestAccelData = it.values.clone() } }
- 销毁服务时清理资源:
override fun onDestroy() { super.onDestroy() uploadHandler.removeCallbacks(uploadTask) val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager sensorManager.unregisterListener(this) measureClient.unregisterHeartRateCallback() }
三、额外注意事项
- 确保已申请传感器权限(Android 10+需
android.permission.ACTIVITY_RECOGNITION)和对应健康数据权限。 - 前台服务+唤醒锁会增加耗电,建议提供用户开关控制后台采集,或在长时间无操作时自动停止服务。
- 网络不稳定时可将数据缓存到本地(如Room数据库),待网络恢复后批量上传。
内容的提问来源于stack exchange,提问作者Gnagno
相关产品推荐
相关产品推荐

