SensorEvent.timestamp不一致

时间:2014-11-04 07:00:07

标签: android android-sensors nanotime

我的应用程序使用android 4.4.X中引入的step detector sensor API's进行后台步骤计数。

我的应用程序必须知道每个步骤事件产生的确切时间(至少准确度为一秒)。

因为我执行了sensor batching,所以调用时间onSensorChanged(SensorEvent event)与步骤事件发生的时间不同 - 我必须使用event.timestamp字段来获取事件时间。< / p>

有关此字段的文档是:

  

事件发生的纳秒时间

问题:

在某些设备(例如Moto X 2013)中,这个时间戳似乎是自启动以来的纳秒时间,而在某些设备(例如Nexus 5)中,它实际上以与System.currentTimeMills() / 1000相同的纳秒为单位返回通用系统时间。

据我所知,已经有 old open issue,但由于引入了传感器批处理 - 使用此字段来了解事件时间变得非常重要,并且不可能依赖已经System.currentTimeMills()

我的问题:

如何在所有设备上始终以系统毫秒为单位获取事件时间?

3 个答案:

答案 0 :(得分:6)

您可以检查event.timestamp是否小于“{2}”,而不是“2天”比较。 1262304000000000000 - 这样,如果过去设置了用户的时钟,或者他们的手机已经运行了40年,那么您只会遇到问题...

除了 this issue上的评论表示有时它甚至是毫秒而不是纳秒。其他评论表明应用了偏移量,在这种情况下,它不会是系统时间或基于正常运行时间。

如果你真的必须准确,我唯一能看到的方法是最初捕获一个事件(或两个,用于比较),max_report_latency_ns设置为0(即非批处理)和将时间戳与系统时间和/或elapsedRealtime进行比较。然后使用该比较来计算偏移量(并可能决定是否需要补偿毫秒与纳秒之间的关系)并将该偏移量用于批处理事件。

E.g。抓住几个事件,最好相隔几秒钟,每次记录System.currentTimeMillis(),然后做这样的事情:

long timestampDelta = event2.timestamp - event1.timestamp;
long sysTimeDelta = sysTimeMillis2 - sysTimeMillis1;
long divisor; // to get from timestamp to milliseconds
long offset; // to get from event milliseconds to system milliseconds

if (timestampDelta/sysTimeDelta > 1000) { // in reality ~1 vs ~1,000,000
    // timestamps are in nanoseconds
    divisor = 1000000;
} else {
    // timestamps are in milliseconds
    divisor = 1;
}

offset = sysTimeMillis1 - (event1.timestamp / divisor);

然后是你的批量活动

long eventTimeMillis = (event.timestamp / divisor) + offset;

最后一点需要注意 - 即使你做了所有这些,如果在捕获过程中系统时间发生变化,也可能会影响你的时间戳。祝你好运!

答案 1 :(得分:3)

根据您提问中的link

  

事实上,这是“按预期工作”。时间戳不是   定义为Unix时间;他们只是“时间”而已   对给定的传感器有效。这意味着时间戳只能是   比较它们是否来自同一传感器。

因此,timestamp - 字段可能与当前系统时间完全无关。

然而;如果在启动时你要拍摄两个传感器样本,没有批处理,你可以计算System.currentTimeMillis()和时间戳之间的差异,以及不同时间之间差异的商数应该能够在不同时间之间进行转换:

//receive event1:
long t1Sys = System.currentTimeMillis();
long t1Evt = event.timestamp;

//receive event2:
long t2Sys = System.currentTimeMillis();
long t2Evt = event.timestamp;

//Unregister sensor


long startoffset = t1Sys - t1Evt; //not exact, but should definitely be less than a second, possibly use an averaged value.
long rateoffset = (t2Sys - t1Sys) / (t2Evt - t1Evt);

现在可以转换来自该传感器的任何时间戳

long sensorTimeMillis = event.timestamp * rateoffset + startoffset;

答案 2 :(得分:2)

我找到了解决问题的解决方法。解决方案假定时间戳只能是两个中的一个:系统时间戳或启动时间:

protected long getEventTimestampInMills(SensorEvent event) {
    long timestamp = event.timestamp / 1000 / 1000;

    /**
     * work around the problem that in some devices event.timestamp is
     * actually returns nano seconds since last boot.
     */
    if (System.currentTimeMillis() - timestamp > Consts.ONE_DAY * 2) {
        /**
         * if we getting from the original event timestamp a value that does
         * not make sense(it is very very not unlikely that will be batched
         * events of two days..) then assume that the event time is actually
         * nano seconds since boot
         */
        timestamp = System.currentTimeMillis()
                + (event.timestamp - System.nanoTime()) / 1000000L;
    }

    return timestamp;
}