3

私は、時計を更新し、特定のタスク(曲の再生など)を別の時間に実行するためのAndroidサービスを担当しています。Timer.scheduleAtFixedRate(new MyTask(), 0, 1000L) などを使用しようとしましたが、1時間で4分以上の遅延が発生しました。
1) var long expectedtNextSystemMilli で System.currentTimeMillis() を使用して開始時刻を記録する2
) この変数に 1 秒 (1000 ミリ秒) を追加して、タスクを再度実行する次の日時を取得する
3) ランナブル内タスクは、タスクの次の実行をスケジュールするために、「実際のシステム時間」と var から予想される時間との間の遅延を計算します。

いくつかのテストの後、遅延の問題もあることに気付き、経過時間を測定するために System.currentTimeMillis() の使用は推奨されておらず、SystemClock.elapsedRealtime() を使用する必要があるというドキュメントを読みました。また、私はそれを行いました。以下は MyTask のコードです

private class MyTask extends TimerTask {
@Override
public void run() {
    Log.i(TAG, "Timer doing work.");
    try {

        // compute the exact next expected system time when MyTask must be executed 
        expectedtNextSystemMilli += 1000L; 

        long delay = expectedtNextSystemMilli - SystemClock.elapsedRealtime() ;

        // countdown update
        counter = counter - 1;

        // !!! sometimes android system is slow and more than 1s is spend before this method is called
        // also we have to test and loop to catch up the delay
        while ( delay < 0){
            Log.e("TimerTick", "ERROR time spent by system in milli = " + delay + "> 1s ");
            expectedtNextSystemMilli += 1000L; 
            delay = expectedtNextSystemMilli - SystemClock.elapsedRealtime() ;
            counter = counter - 1;
        }

        // test if countdown is finished
        if ( counter <=0 ){

            mTimer.cancel();
            onFinish();

        }else{

            // send message to listeners
            onTick(counter);

            // update the delay with the new system time (in case the call to onTick has been long)
            delay = expectedtNextSystemMilli - SystemClock.elapsedRealtime() ;

            // schedule the next execution of this task
            mTimer.schedule(new MyTask(), delay);
            Log.d("TimerTick", "new delay in milli is " + delay+", elapsedRealtime = "+ SystemClock.elapsedRealtime() );
        }

    } catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
        Log.e("TimerTick", "Timer Tick Failed. Raison: "+ t.getMessage());            
    }
}       
}

このコードをたどると、ご覧のように SystemClock.elapsedRealtime() によって 28 秒のジャンプが返されることに驚きました。

07-13 22:15:00.041: V/TimerManagerService(19377): onTick 遅延 = 361 終了、トレース = 539
07-13 22:15:00.041 : D/TimerTick(19377): ミリ単位の新しい遅延は 999、経過リアルタイム = 84800078
07-13 22:15:01.041: I/TimerManagerService(19377): タイマーが動作しています。
07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -28585> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間ミリ = -27585> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -26586> 1
秒 07-13 22:15:01.041: E/TimerTick(19377):システムがミリ単位で費やしたエラー時間 = -25586> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムがミリ単位で費やしたエラー時間 = -23587> 1 秒
07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -22587> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間ミリ = -21588> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -20588> 1
秒 07-13 22:15:01.041: E/TimerTick(19377):システムが費やしたエラー時間 (ミリ単位) = -19589> 1
秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -18589> 1
秒 07-13 22:15:01.041: E /TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -17589> 1 秒
07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -16590> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間ミリ = -15590> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -14591> 1 秒 07-13 22:15:01.041: E/TimerTick(19377):システムが費やしたエラー時間 (ミリ単位) = -13591> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -12591> 1 秒 07-13 22:15:01.041: E /TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -11592> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位 = -10592> 1 秒 07-13 22 :15:01.041: E/TimerTick(19377): システムで費やされたエラー時間 (ミリ単位) = -9592> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムで費やされたエラー時間 (ミリ単位) = -8593 > 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -7594> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -6594> 1 秒 07 -13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -5595> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -4596> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -3596> 1 秒 07-13 22:15:01.041: E/TimerTick(19377): エラーシステムがミリ単位で費やした時間 = -24586> 1 秒 07-13 22:15:01.051: E/TimerTick(19377): システムがミリ単位で費やしたエラー時間 = -2597> 1 秒 07-13 22:15:01.051: E/ TimerTick(19377): システムが費やしたエラー時間 (ミリ単位) = -1598> 1 秒 07-13 22:15:01.051: E/TimerTick(19377): システムが費やしたエラー時間 (ミリ単位 = -598> 1 秒 07-13 22: 15:01.051:V/TimerManagerService(19377): onTick 遅延 = 331 終了、トレース = 540
07-13 22:15:01.051 : D/TimerTick(19377): ミリ単位の新しい遅延は 400、経過リアルタイム = 84830677
07-13 22:15:01.450: I/TimerManagerService(19377): タイマーが動作しています。

1) ログ: 07-13 22:15:00.041 : D/TimerTick(19377): ミリ単位の新しい遅延は 999、elapsedRealtime = 84800078
はスケジュールの直後に run() にある schedule => mTimer.schedule(new MyTask( )、 遅れ);

2) 同じ run() の呼び出しをスケジュールしますが、それを行うのに 28 秒以上かかるようです
ただし、日食レポートは 1 秒のみ => 22:15:00.041 2 つの呼び出しの間に 22:15:01.041

また、Androidで正確な経過時間を取得するには何を使用する必要があると思いますか?

4

2 に答える 2