【问题标题】:How to measure elapsed time如何测量经过的时间
【发布时间】:2013-03-06 13:39:28
【问题描述】:

我有一个 10 和 20 题的游戏。我需要计算用户完成游戏时经过了多少时间。

Timer T=new Timer();
T.scheduleAtFixedRate(new TimerTask() {         
    @Override
    public void run() {
        runOnUiThread(new Runnable()
        {                
            public void run()
            {
                countdown.setText(""+count);
                count++;                
            }
        });
    }
}, 1000, 1000);

我用它来停止计数器:

T.cancel();

现在我需要两件事:

  • 一种计算经过时间并将其存储在变量中的方法
  • 我需要最终值是双倍,例如最终得分是:15.49 秒。

【问题讨论】:

标签: java android


【解决方案1】:

根据 Android docs SystemClock.elapsedRealtime() 是通用间隔计时的推荐依据。这是因为,根据文档, elapsedRealtime() is guaranteed to be monotonic, [...], so is the recommend basis for general purpose interval timing.

SystemClock documentation 很好地概述了各种时间方法及其适用的用例。

  • SystemClock.elapsedRealtime()SystemClock.elapsedRealtimeNanos() 是计算通用经过时间的最佳选择。
  • SystemClock.uptimeMillis()System.nanoTime() 是另一种可能性,但与推荐的方法不同,它们不包括深度睡眠时间。如果这是您想要的行为,那么它们可以使用。否则坚持使用elapsedRealtime()
  • 远离System.currentTimeMillis(),因为这将返回“挂钟”时间。这不适合计算经过的时间,因为挂钟时间可能会向前或向后跳跃。诸如 NTP 客户端之类的许多事情都可能导致挂钟时间跳跃和歪斜。这将导致基于currentTimeMillis() 的经过时间计算并不总是准确的。

游戏开始时:

long startTime = SystemClock.elapsedRealtime();

游戏结束时:

long endTime = SystemClock.elapsedRealtime();
long elapsedMilliSeconds = endTime - startTime;
double elapsedSeconds = elapsedMilliSeconds / 1000.0;

另外,Timer() 是一个尽力而为的计时器,并不总是准确的。因此,在比赛期间会累积计时错误。为了更准确地显示中间时间,请使用定期检查 System.currentTimeMillis() 作为发送到 setText(...) 的时间的基础。

另外,你可能想研究使用TimerTask,而不是使用Timer,这个类是为你想做的事情而设计的。唯一的问题是它倒计时而不是倒计时,但这可以通过简单的减法来解决。

【讨论】:

  • 这是正确答案。接受的实际上是错误的。
【解决方案2】:

游戏开始时:

long tStart = System.currentTimeMillis();

游戏结束时:

long tEnd = System.currentTimeMillis();
long tDelta = tEnd - tStart;
double elapsedSeconds = tDelta / 1000.0;

【讨论】:

  • Per the documentation: System.currentTimeMillis() is the standard "wall" clock (time and date) expressing milliseconds since the epoch. The wall clock can be set by the user or the phone network (see setCurrentTimeMillis(long)), so the time may jump backwards or forwards unpredictably. 所以System.currentTimeMillis() 是实施经过时间的糟糕选择。
  • @Benjamin 你有什么建议?
  • 每Android docsSystemClock.elapsedRealtime() 是recommend basis for general purpose interval timing.
  • 正如其他人所说,下面的elapsedRealtime() 答案是正确的。这个是错的。
【解决方案3】:

更好!

long tStart = System.nanoTime();
long tEnd = System.nanoTime();
long tRes = tEnd - tStart; // time in nanoseconds

阅读documentation 关于 nanoTime()!

【讨论】:

  • 如果您提到新内容,很高兴提供文档链接
  • 根据this other question,这个答案可能是最好的答案。
【解决方案4】:

从 Java 8 开始,您可以尝试以下操作:

import java.time.*;
import java.time.temporal.ChronoUnit;

Instant start_time = Instant.now();
// Your code
Instant stop_time = Instant.now();

System.out.println(Duration.between(start_time, stop_time).toMillis());

//or

System.out.println(ChronoUnit.MILLIS.between(start_time, stop_time));

【讨论】:

    【解决方案5】:

    有很多方法可以实现这一点,但衡量经过时间的最重要考虑因素是使用System.nanoTime()TimeUnit.NANOSECONDS 作为时间单位。 我为什么要这样做?嗯,这是因为System.nanoTime() 方法返回一个高分辨率的时间源,从某个参考点(即 Java 虚拟机启动)开始以纳秒为单位。

    此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。

    出于同样的原因,建议避免使用System.currentTimeMillis() 方法来测量经过时间。此方法返回wall-clock 时间,该时间可能会因许多因素而变化。这将对您的测量结果不利。

    请注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能更大。例如,许多操作系统以几十毫秒为单位测量时间。

    所以这里有一个基于System.nanoTime() 方法的解决方案,另一个使用Guava 的解决方案,最后一个是Apache Commons Lang

    public class TimeBenchUtil
    {
        public static void main(String[] args) throws InterruptedException
        {
            stopWatch();
            stopWatchGuava();
            stopWatchApacheCommons();
        }
    
        public static void stopWatch() throws InterruptedException
        {
            long endTime, timeElapsed, startTime = System.nanoTime();
    
            /* ... the code being measured starts ... */
    
            // sleep for 5 seconds
            TimeUnit.SECONDS.sleep(5);
    
            /* ... the code being measured ends ... */
    
            endTime = System.nanoTime();
    
            // get difference of two nanoTime values
            timeElapsed = endTime - startTime;
    
            System.out.println("Execution time in nanoseconds   : " + timeElapsed);
        }
    
        public static void stopWatchGuava() throws InterruptedException
        {
            // Creates and starts a new stopwatch
            Stopwatch stopwatch = Stopwatch.createStarted();
    
            /* ... the code being measured starts ... */
    
            // sleep for 5 seconds
            TimeUnit.SECONDS.sleep(5);
            /* ... the code being measured ends ... */
    
            stopwatch.stop(); // optional
    
            // get elapsed time, expressed in milliseconds
            long timeElapsed = stopwatch.elapsed(TimeUnit.NANOSECONDS);
    
            System.out.println("Execution time in nanoseconds   : " + timeElapsed);
        }
    
        public static void stopWatchApacheCommons() throws InterruptedException
        {
            StopWatch stopwatch = new StopWatch();
            stopwatch.start();
    
            /* ... the code being measured starts ... */
    
            // sleep for 5 seconds
            TimeUnit.SECONDS.sleep(5);
    
            /* ... the code being measured ends ... */
    
            stopwatch.stop();    // Optional
    
            long timeElapsed = stopwatch.getNanoTime();
    
            System.out.println("Execution time in nanoseconds   : " + timeElapsed);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-13
      • 2019-12-30
      • 1970-01-01
      • 1970-01-01
      • 2017-09-20
      相关资源
      最近更新 更多