2014-11-04 116 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