2014-11-04 28 views
12

Meine Anwendung führt im Hintergrund Schrittzähler mit der in Android 4.4.X eingeführt step detector sensor API's.SensorEvent.timestamp Inkonsistenz

Es ist wichtig für meine App zu wissen, die genaue Zeit (mindestens Genauigkeit einer Sekunde) jedes Schritt Ereignis ist angesammelt.

weil ich sensor batching durchführen, die Zeit onSensorChanged(SensorEvent event) wurde nicht die gleiche Zeit wird aufgerufen, wenn der Schritt Ereignis stattfand - ich muß das event.timestamp Feld verwenden, um die Ereigniszeit zu bekommen.

die Dokumentation zu diesem Bereich ist:

Die Zeit in Nanosekunden an dem das Ereignis

Das Problem passiert:

Bei einigen Geräten (wie Moto X 2013) scheint, als wäre dieser Zeitstempel die Zeit in Nanosekunden seit dem Booten, während in einigen Geräten (wie Nexus 5) tatsächlich die universelle Systemzeit in Nanosekunden wie System.currentTimeMills()/1000 zurückgegeben wird.

Ich verstehe, gibt es bereits ein old open issue darüber, aber da der Sensor batching eingeführt wird - es wichtig wird dieses Feld zu verwenden, um die Ereigniszeit zu kennen, und es ist nicht mehr möglich, auf die System.currentTimeMills()

verlassen Meine Frage:

Was soll ich tun, um immer die Ereigniszeit in System Millisekunden über alle Geräte zu erhalten?

Antwort

4

Statt Ihre „2-Tages“ Vergleich, könnten Sie einfach überprüfen, ob event.timestamp kleiner als z 1262304000000000000 - auf diese Weise nur ein Problem haben würde, wenn die Uhr des Benutzers in der Vergangenheit festgelegt ist, oder ihr Telefon 40 Jahre läuft ...

Außer dass ein Kommentar auf this issue zeigt an, dass es manchmal sogar Millisekunden statt Nanosekunden. Andere Kommentare weisen darauf hin, dass ein Offset angewendet wird. In diesem Fall wird weder die Systemzeit noch die Verfügbarkeit berücksichtigt.

Wenn Sie wirklich genau sein müssen, ist die einzige Art, wie ich sehen kann, ist zunächst ein Ereignis zu erfassen (oder zwei, zum Vergleich) mit max_report_latency_ns Satz 0 (dh nicht chargiert) und den Zeitstempel auf die Systemzeit vergleichen und/oder elapsedRealtime. Verwenden Sie dann diesen Vergleich, um einen Offset zu berechnen (und möglicherweise zu entscheiden, ob Sie Millisekunden oder Nanosekunden kompensieren müssen), und verwenden Sie diesen Offset für Ihre Batch-Ereignisse.

z.greifen ein paar Ereignisse, vorzugsweise ein paar Sekunden auseinander, die Aufnahme der System.currentTimeMillis() jedes Mal, und dann etwas tun, wie folgt aus:

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); 

Und dann für Ihre batched Ereignisse

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

Eine letzte Einschränkung - auch Wenn Sie dies alles tun, kann sich die Systemzeit während der Erfassung ändern, was sich auf Ihre Zeitstempel auswirken kann. Viel Glück!

+0

Ich glaube, Ihre Lösung ist die beste Antwort, die ich bekommen konnte. Danke –

+0

Wow, das ist unglaublich. – Michael

2

Ich habe eine Lösung gefunden, die das Problem löst. die Lösung wird davon ausgegangen, dass der Zeitstempel nur einer der beiden sein kann: Systemzeitstempel oder Bootzeit:

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

wie ein Hack Smells umgewandelt werden. –

2

Nach den link in Ihrer Frage:

Dies ist in der Tat "wie beabsichtigt". Die Zeitstempel sind nicht definiert als Unix-Zeit; sie sind nur "eine Zeit" das ist nur gültig für einen bestimmten Sensor. Dies bedeutet, dass Zeitstempel nur verglichen werden können, wenn sie vom selben Sensor kommen.

So könnte das timestamp -Feld völlig unabhängig von der aktuellen Systemzeit sein.

Jedoch; wenn beim Start zwei Sensor Proben nehmen sind, ohne Dosierung, könnte man den Unterschied zwischen den System.currentTimeMillis() und dem Zeitstempel, sowie der Quotienten auf die Unterschiede zwischen den verschiedenen Zeiten berechnen sollten Sie in der Lage sein, zwischen den verschiedenen Zeiten zu konvertieren :

//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); 

Nun kann jeder Zeitstempel von diesem Sensor kann

long sensorTimeMillis = event.timestamp * rateoffset + startoffset; 
+0

Ich sehe, dass wir sehr ähnlich gedacht haben. Ich könnte mir vorstellen, Ihre 'rateoffset' Berechnung obwohl in Drift über die Zeit führen (die weiter voneinander entfernt die Probe Ereignisse der weniger ein Problem, das sein sollte, aber es wird nie perfekt sein, vor allem, weil es eine unvorhersehbare Verzögerung zwischen der Ereigniszeit sein und die zugehörige Systemzeit). Deshalb habe ich es in meiner Antwort entweder auf 1 oder auf 1.000.000 geklemmt. – CupawnTae

+0

Ja, ich lese durch Ihre Antwort Ich weiß, es ist im Grunde die gleiche Idee. Wenn man den Wert klemmt, wird das Problem mit der Drift definitiv gelöst, aber ein Durchschnitt von mehreren Proben in Kombination mit periodischen Neuberechnungen ist eine Alternative, die in Betracht gezogen werden kann, je nachdem, was benötigt wird. – Jave

+0

das ist empörend! – Michael