2014-11-04 109 views
12

我的应用程序使用Android 4.4.X中引入的step detector sensor API's在后台步数计数中执行。SensorEvent.timestamp不一致

对于我的应用程序来说,了解每个步骤事件产生的确切时间(至少精确度)至关重要。

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

了解这个字段的文档是:

在纳秒的时间在该事件发生

问题:

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

我明白了,有已经是一个 old open issue有关,但由于传感器配料介绍 - 成为使用此字段知道事件的时间很重要,它不可能再依靠System.currentTimeMills()

我的问题:

我应该怎么做才能在所有设备上获得系统毫秒级的事件时间?

回答

4

而是你的“2天”的比较,你可以只检查是否event.timestamp小于例如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; 

最后一个警告 - 甚至如果你这样做了,如果系统时间在捕获过程中发生变化,它可能会影响你的时间戳。祝你好运!

+0

我相信你的解决方案是我能得到的最佳答案。谢谢 – 2015-04-08 17:12:22

+0

哇,这是令人难以置信的。 – Michael 2017-10-09 04:23:57

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; 
} 
+0

闻起来像一劈。 – 2015-04-07 15:27:29

2

根据你的问题link

这,其实, “如预期运行”。时间戳不是定义为Unix时间的 ;他们只是“一次”,只有 对于给定的传感器有效。这意味着如果时间戳来自同一个传感器,则时间戳只能是 。

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

但是;如果在启动时您要采集两个传感器样本,而没有批处理,则可以计算出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; 
+0

我看到我们一直在思考非常类似的问题。我认为你的'rateoffset'计算会导致随着时间的推移而发生偏差(样本事件越离开这个问题应该是越少的问题,但它永远不会是完美的,特别是因为在事件时间之间会有不可预测的延迟和相关的系统时间)。这就是为什么在我的回答中,我把它夹到1或1,000,000。 – CupawnTae 2015-04-08 10:08:48

+0

是的,通读你的口水我意识到这是基本相同的想法。限制数值肯定可以解决漂移问题,但取决于需要,平均数个样本与定期重新计算是可以考虑的替代方案。 – Jave 2015-04-08 11:19:42

+0

这是反叛! – Michael 2017-10-09 04:53:43