Несоответствие SensorEvent.timestamp
мое приложение выполняет подсчет фонового шага с использованием API-интерфейса датчика детектора шага, представленного в android 4.4.X.
Для моего приложения важно знать точное время (по крайней мере, с точностью до секунды) каждое событие шага.
потому что я выполняю пакетное дозирование, время onSensorChanged(SensorEvent event)
было вызвано не то же самое время, когда произошло событие шага - я должен использовать поле event.timestamp
для получения времени события.
документация об этом поле:
Время в наносекундах, при котором произошло событие
Проблема:
В некоторых устройствах (например, Moto X 2013) кажется, что эта временная метка - это время в nano секундах с момента загрузки, в то время как в некоторых устройствах (например, Nexus 5) она фактически возвращает универсальное системное время в nano секундах так же, как System.currentTimeMills() / 1000
.
Я понимаю, там уже есть старая открытая проблема, но поскольку введен пакетный пакет - , важно использовать это поле знать время события, и больше нельзя полагаться на System.currentTimeMills()
Мой вопрос:
Что делать, чтобы всегда получать время события в системных миллисекундах на всех устройствах?
Ответы
Ответ 1
Вместо сравнения "2 дня" вы можете просто проверить, меньше ли event.timestamp
, например. 1262304000000000000
- таким образом у вас будет только проблема, если пользовательские часы установлены в прошлом, или их телефон работает в течение 40 лет...
За исключением того, что комментарий этот вопрос указывает, что иногда это даже миллисекунды вместо наносекунд. И другие комментарии указывают на то, что применяется смещение, и в этом случае он не будет ни системным, ни временным временем.
Если вам действительно нужно быть точным, единственный способ, по которому я могу видеть, - это сначала зафиксировать событие (или два для сравнения) с max_report_latency_ns
, установленным на 0
(то есть без пакета), и сравнить временную метку с системное время и/или elapsedRealtime
. Затем используйте это сравнение, чтобы вычислить смещение (и, возможно, решить, нужно ли вам компенсировать миллисекунды против наносекунд) и использовать это смещение для ваших пакетных событий.
например. захватите пару событий, желательно на пару секунд, записывая 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;
Одно последнее предупреждение - даже если вы все это сделаете, если системное время изменится во время вашего захвата, оно может повлиять на ваши метки времени. Удачи!
Ответ 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;
}
Ответ 3
В соответствии с ссылка в вашем вопросе:
Это, по сути, "работает по назначению". Временные метки не являются определяемый как время 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;