16

私のアプリケーションは、Android 4.4.X で導入されたステップ検出センサー APIを使用して、バックグラウンドでステップ カウントを実行します。

各ステップ イベントが発生した正確な時間 (少なくとも 1 秒の精度) を知ることは、私のアプリにとって不可欠です。

センサーのバッチ処理を実行するため、呼び出された時間onSensorChanged(SensorEvent event)は、ステップ イベントが発生した時間と同じではありませんevent.timestamp。フィールドを使用してイベント時間を取得する必要があります。

このフィールドに関するドキュメントは次のとおりです。

イベントが発生したナノ秒単位の時間

問題:

一部のデバイス (Moto X 2013 など) では、このタイムスタンプは起動後のナノ秒単位の時間のように見えますが、一部のデバイス (Nexus 5 など) では、実際には と同じナノ秒単位のユニバーサル システム時間を返しますSystem.currentTimeMills() / 1000

それについてはすでに未解決の問題があることは承知していますが、センサーのバッチ処理が導入されてから、このフィールドを使用してイベント時間を知ることが重要になり、System.currentTimeMills()

私の質問:

すべてのデバイスで常にシステム ミリ秒単位のイベント時間を取得するにはどうすればよいですか?

4

3 に答える 3

7

「2日間」の比較の代わりに、event.timestamp例えばより少ないかどうかを確認することができます1262304000000000000-そのようにすると、ユーザーの時計が過去に設定されている場合、または電話が40年間動作している場合にのみ問題が発生します.. .

この問題に関するコメントが、ナノ秒ではなくミリ秒である場合があることを示していることを除いて。また、他のコメントは、オフセットが適用されていることを示しています。この場合、システム時間または稼働時間ベースではありません.

あなたが本当に正確でなければならない場合、私が見ることができる唯一の方法は、最初に にmax_report_latency_ns設定されたイベント (または比較のために 2 つ) をキャプチャ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;

最後に 1 つ注意点があります。これを行ったとしても、キャプチャ中にシステム時間が変更されると、タイムスタンプに影響する可能性があります。幸運を!

于 2015-04-07T23:57:43.273 に答える
4

問題を解決する回避策を見つけました。このソリューションでは、タイムスタンプがシステム タイムスタンプまたは起動時間のいずれかであると想定しています。

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;
}
于 2014-11-11T06:17:09.807 に答える
3

あなたの質問のリンクによると:

実際、これは「意図したとおりに機能している」ということです。タイムスタンプは Unix 時間として定義されていません。それらは、特定のセンサーに対してのみ有効な「時間」にすぎません。これは、タイムスタンプが同じセンサーからのものである場合にのみ比較できることを意味します。

そのため、timestampフィールドは現在のシステム時刻とはまったく無関係である可能性があります。

でも; 起動時に、バッチ処理を行わずに 2 つのセンサー サンプルを取得する場合、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;
于 2015-04-08T09:12:53.503 に答える