You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android前台服务存储传感器数据时出现时间跳变问题排查

问题:传感器数据存储出现时间跳变现象

我正在开发一款应用,使用前台服务监控传感器数据并将其存储到Realm数据库中,每秒存储一次包含所有传感器值的对象。通过初始化SensorEventListener监听传感器事件,采用Channel架构以流的方式收发传感器数据。目前遇到的问题是,数据库存储中会出现时间跳变现象,尽管已关闭应用的电池优化,但问题仍存在,跳变间隔约15-20分钟,有时分布更随机。

相关代码片段

accelometerSensorEventListener = object : SensorEventListener {
    override fun onSensorChanged(event: SensorEvent?) {
        if (true) {
            for (i in 0 until event!!.values.size) {
                accelerometerValues[i] = event.values[i]
                Log.d("DATA", "accelerometer value : ${event.values[i]}")
            }

            //keep the time stamp for each event
            if (!acceleratorTimeStampSet) {
                acceleratorTimeStampSet = true
                initialAcceleratorTimeStamp = System.currentTimeMillis()
            }
            //set the timestamps
            ...
            allTimeStamps.add(dateTime.toString())
        }

        var sensors = Sensors()
        var accelX = String.format("%.4f", event!!.values.get(0)).replace(",", ".")
        var accelY = String.format("%.4f", event!!.values.get(1)).replace(",", ".")
        var accelZ = String.format("%.4f", event!!.values.get(2)).replace(",", ".")
        sensors.accelerationXAxisValue = accelX
        sensors.accelerationYAxisValue = accelY
        sensors.accelerationZAxisValue = accelZ
        sensors.timeStamp = allTimeStampsAccel.get(allTimeStampsAccel.size -1)

        writeStringToFile("accel : $accelX\n")
        data.trySend(sensors)
}

fun collectSensorDataFromChannelAndStoreToRealmDB() {
    val scope = CoroutineScope(Dispatchers.Default)
    var sensorFecthingComplete : Boolean = false
    var sensors = Sensors()

    scope.launch {
        while (true) {
            var flowedSensors = data.receive()

            if (flowedSensors.accelerationXAxisValue != null) {
                sensors.accelerationXAxisValue = flowedSensors.accelerationXAxisValue
            }
            if (flowedSensors.accelerationYAxisValue != null) {
                sensors.accelerationYAxisValue = flowedSensors.accelerationYAxisValue
            }
            
             ...

            if ((sensors.accelerationXAxisValue != null) && (sensors.accelerationYAxisValue != null)
                &&  (sensors.accelerationZAxisValue != null) && (sensors.gyroscopeXAxis != null)
                && (sensors.gyroscopeYAxis != null) && (sensors.gyroscopeZAxis != null)
                && (sensors.linAcceXAxiValue != null) && (sensors.linAccelYAxisValue != null)
                && (sensors.linAccelZAxisValue != null) && (sensors.rotationXAxis != null) && (sensors.rotationYAxis != null)
                && (sensors.rotationZAxis != null) && (sensors.scalarRotation != null) && (sensors.pitch != null) && (sensors.roll != null)
                && (sensors.azimuth != null))
                sensorFecthingComplete = true

            //store the sensor data to realm database
            if (sensorFecthingComplete) {
                realmDB = Realm.getDefaultInstance()
                val num : Number? = realmDB.where(Sensors::class.java).max("id")
                Log.d("STORE", "new ID num : ${num}")
                var nextID : Int = 0
                nextID = if (num == null) {
                    1
                } else {
                    num.toInt() + 1
                }
                if (nextID >= 2) {
                    val currentSensor : Sensors = realmDB.where(Sensors::class.java).equalTo("id", nextID -1).findFirst()!!
                    val currentTimeStamp = currentSensor.timeStamp
                    var previousHour = LocalDateTime.parse(currentTimeStamp, DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a"))
                    // var previousHour = SimpleDateFormat("YYYY-MM-d hh:mm:ss a").parse(currentTimeStamp)
                    var currentHour = LocalDateTime.parse(sensors.timeStamp, DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a"))
                    // var currentHour = SimpleDateFormat("YYYY-MM-d hh:mm:ss a").parse(sensors.timeStamp)

                    if (currentHour.isAfter(previousHour)) {
                        try {
                            realmDB.executeTransaction {
                                sensors.id = nextID
                                if (realmDB.where(Sensors::class.java).equalTo("id", sensors.id).findFirst() == null) {
                                    Log.d("DATA", "sensors storing with id : ${sensors.id}")
                                    writeStringToFile("storing sensor id : " + sensors.id+"\n")
                                    realmDB.insert(sensors)
                                }
                            }
                        } catch(e : Exception) {
                            Log.d("EXCEPTION", e.message.toString())
                        }
                    }
                } else {
                    var dummySensors = Sensors()
                    dummySensors.id = 1
                    var now = LocalDateTime.now()
                    var currentTimeStamp = DateTimeFormatter.ofPattern("YYYY-MM-dd hh:mm:ss a")
                    val currentDate = now.format(currentTimeStamp)
                    // var time = SimpleDateFormat("YYYY-MM-d hh:mm:ss a").parse(Calendar.getInstance().time.toString()).toString()
                    dummySensors.timeStamp = currentDate.toString()
                    dummySensors.accelerationXAxisValue = null
                    dummySensors.accelerationYAxisValue = null

                    ...

                    realmDB.executeTransaction {
                        it.insert(dummySensors)
                    }
                }
                sensorFecthingComplete = false
                sensors.timeStamp = null
                sensors.accelerationXAxisValue = null
                sensors.accelerationYAxisValue = null
                sensors.accelerationZAxisValue = null

                ...
            }
        }
    }
}

时间跳变的可能原因

  • 传感器采样率不稳定:SensorEventListener的回调频率并非严格固定为每秒一次,系统会根据硬件负载、进程优先级动态调整传感器采样率。即使是前台服务,当系统资源紧张时,传感器回调可能被延迟,导致批量数据集中发送到Channel,最终存储时时间戳出现跳变。
  • Channel数据积压与消费延迟:如果collectSensorDataFromChannelAndStoreToRealmDB中的协程在处理/存储数据时耗时(比如Realm事务阻塞),Channel会积压传感器事件。当积压的数据被批量处理时,时间戳就会出现连续跳变。
  • 时间戳生成逻辑不一致:当前代码中传感器数据的时间戳依赖allTimeStampsAccel列表的最后一个元素,若传感器事件回调延迟,这个列表的时间戳可能不是实时生成,而是在回调触发时批量补充,导致时间戳不连续。另外,dummy数据使用LocalDateTime.now()生成时间戳,和传感器事件的时间戳来源不一致,也可能引入跳变。
  • Realm事务的性能瓶颈:每次存储都调用Realm.getDefaultInstance()获取实例,且事务中存在重复查询操作(equalTo("id", sensors.id)),如果事务执行缓慢,会导致后续数据处理延迟,进而让时间戳看起来跳变。
  • 厂商系统深层限制:即使关闭了应用级电池优化,部分厂商的系统仍有全局后台限制策略(如待机模式、应用休眠),会在后台静默限制传感器采样或进程调度,导致数据采集中断后恢复时出现时间跳变。

内容的提问来源于stack exchange,提问作者Lampros Marantos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 08:20:17