简体   繁体   English

用Java制作一个简单的计时器

[英]Make a simple timer in Java

I can't seem to figure out how to make a simple timer in java.我似乎无法弄清楚如何在 java 中制作一个简单的计时器。 All I need it to do is just display time, really.我需要它做的只是显示时间,真的。 So just a start method, and it keeps counting up like 0:00, 0:01, 0:02, etc. I've seen some other similar forum posts on this, but all the code is kind of complicated for my level of understanding;所以只是一个开始方法,它一直在计数,比如 0:00、0:01、0:02 等。我已经看到了一些其他类似的论坛帖子,但所有代码对于我的水平来说都有点复杂理解; I'm kind of new to java.我对java有点陌生。 But it shouldnt be that hard to make a timer that just performs such a basic function?但是做一个只执行这样一个基本功能的计时器应该不难吧? If anyone could help it would be greatly appreciated :)如果有人可以提供帮助,将不胜感激:)

This is not difficult.这并不难。 However, I would caution you that I have seen some very confused answers on stack overflow, in some cases shockingly poor coding habits, so be very careful.但是,我要提醒您,我在堆栈溢出方面看到了一些非常混乱的答案,在某些情况下,编码习惯非常糟糕,所以要非常小心。 First let me answer the question.首先让我回答这个问题。

If seem that the biggest mistake that programmers make in implementing a timer, is thinking that they need something to keep track of the current time.如果程序员在实现计时器时犯的最大错误似乎是认为他们需要一些东西来跟踪当前时间。 That is, they write some sort of loop that increments a variable every second or some such silly thing.也就是说,他们编写了某种循环,每秒增加一个变量或一些类似的傻事。 You do not need to write code to keep track of the time.您无需编写代码来跟踪时间。 The function System.currentTimeMillis() will do that for you, and it does it quite accurately.函数System.currentTimeMillis()会为你做这件事,而且做得非常准确。

Timer code will involve two aspects which many programmers mix up:定时器代码将涉及许多程序员混淆的两个方面:

  1. calculation of the time时间的计算
  2. refresh of the display刷新显示

All you need to do to calculate the time to display, is to record the time that the timer started:计算显示时间所需要做的就是记录计时器开始的时间:

long startTime = System.currentTimeMillis();

Later, when you want to display the amount of time, you just subtract this from the current time.稍后,当您想要显示时间量时,只需从当前时间中减去它即可。

long elapsedTime = System.currentTimeMillis() - startTime;
long elapsedSeconds = elapsedTime / 1000;
long secondsDisplay = elapsedSeconds % 60;
long elapsedMinutes = elapsedSeconds / 60;
//put here code to format and display the values

The biggest mistake that programmers make is to think they need a variable to hold the current time and then to write code to increment that variable every second, eg something called "elapsedSeconds" which they maintain.程序员犯的最大错误是认为他们需要一个变量来保存当前时间,然后编写代码以每秒递增该变量,例如他们维护的称为“elapsedSeconds”的东西。 The problem is that you can schedule code to be called every second, but there is no guarantee of exactly when that code will be called.问题是您可以安排每秒调用一次代码,但不能保证准确地调用该代码的时间。 If the system is busy, that code might be called quite a bit later than the second.如果系统很忙,则调用该代码的时间可能会比第二个稍晚一些。 If the system is extremely busy (for example page fetching from a faulty disk) it could actually be several seconds late.如果系统非常繁忙(例如从故障磁盘中获取页面),它实际上可能会延迟几秒钟。 Code that uses the Thread.sleep(1000) function to loop every second will find that the error builds up over time.使用 Thread.sleep(1000) 函数每秒循环的代码会发现错误会随着时间的推移而累积。 If sleep returns 300ms late one time, that error is compounded into your calculation of what time it is.如果 sleep 有一次延迟返回 300 毫秒,则该错误会复合到您计算现在的时间中。 This is all completely unnecessary because the OS has a function to tell you the current time .这完全没有必要,因为操作系统有告诉你当前时间的功能

The above calculation will be accurate whether you run this code every second, 100 times a second, or once every 3.572 seconds.无论您每秒运行此代码、每秒运行 100 次还是每 3.572 秒运行一次,上述计算都是准确的。 The point is that currentTimeMillis() is the accurate representation of the time regardless of when this code is called -- and that is an important consideration because thread and timer events are not guaranteed to be accurate at a specific time.关键是currentTimeMillis()是时间的准确表示,无论何时调用此代码——这是一个重要的考虑因素,因为不能保证线程和计时器事件在特定时间是准确的。

The second aspect of a timer is refresh of the display.计时器的第二个方面是刷新显示。 This will depend upon the technology you are using to display with.这将取决于您用于显示的技术。 In a GUI environment you need to schedule paint events.在 GUI 环境中,您需要安排绘制事件。 You would like these paint events to come right after the time that the display is expected to change.您希望这些绘制事件在预期显示更改的时间之后立即出现。 However, it is tricky.但是,这很棘手。 You can request a paint event, but there may be hundreds of other paint events queued up to be handled before yours.您可以请求绘制事件,但可能有数百个其他绘制事件排队等待处理。

One lazy way to do this is to schedule 10 paint events per second.一种懒惰的方法是每秒安排 10 个绘制事件。 Because the calculation of the time does not depend on the code being called at a particular point in time, and because it does not matter if you re-paint the screen with the same time, this approach more or less guarantees that the displayed time will show the right time within about 1/10 of a second.因为时间的计算不依赖于在特定时间点被调用的代码,而且如果你用相同的时间重新绘制屏幕也没关系,这种方法或多或少保证了显示的时间会在大约 1/10 秒内显示正确的时间。 This seems a bit of a waste, because 9 times out of 10 you are painting what is already on the screen.这似乎有点浪费,因为 10 次中有 9 次是在绘制屏幕上已有的内容。

If you are writing a program with animation of some sort (like a game) which is refreshing the screen 30 times a second, then you need do nothing.如果您正在编写一个带有某种动画(如游戏)的程序,该程序每秒刷新屏幕 30 次,那么您无需执行任何操作。 Just incorporate the timer display call into your regular screen refresh.只需将计时器显示调用合并到您的常规屏幕刷新中即可。

If paint events are expensive, or if you are writing a program that does terminal-style output, you can optimize the scheduling of events by calculating the amount of time remaining until the display will change:如果绘制事件很昂贵,或者如果您正在编写一个执行终端样式输出的程序,您可以通过计算显示更改之前的剩余时间来优化事件的调度:

long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);

The variable timeTillNextDisplayChange holds the number of milliseconds you need to wait until the seconds part of the timer will change.变量 timeTillNextDisplayChange 保存您需要等待的毫秒数,直到计时器的秒部分发生变化。 You can then schedule a paint event to occur at that time, possibly calling Thread.sleep(timeTillNextDisplayChange) and after the sleep do the output.然后,您可以安排在那个时候发生绘制事件,可能调用Thread.sleep(timeTillNextDisplayChange)并在睡眠后执行输出。 If your code is running in a browser, you can use this technique to update the page DOM at the right time.如果您的代码在浏览器中运行,您可以使用此技术在正确的时间更新页面 DOM。

Note, that there is nothing in this calculation of the display refresh that effects the accuracy of the timer itself.请注意,此显示刷新计算中没有任何内容会影响计时器本身的准确性。 The thread might return from sleep 10ms late, or even 500ms late, and the accuracy of the timer will not be effected.线程可能会延迟 10ms 甚至 500ms 从睡眠中返回,并且不会影响计时器的准确性。 On every pass we calculate the time to wait from the currentTimeMillis, so being called late on one occasion will not cause later displays to be late.每次通过时,我们都会从 currentTimeMillis 计算等待时间,因此一次调用迟到不会导致稍后的显示迟到。

That is the key to an accurate timer.这是精确计时器的关键。 Do not expect the OS to call your routine or send the paint event exactly when you ask it to.不要指望操作系统会在您要求时调用您的例程或发送绘图事件。 Usually, of course, with modern machines, the OS is remarkably responsive and accurate.当然,通常,对于现代机器,操作系统的响应速度非常快且准确。 This happens in test situations where you are not running much else, and the timer seems to work.这发生在您没有运行太多其他东西并且计时器似乎工作的测试情况下。 But, in production, under rare stress situation, you do not want your timer "drifting" because the system is busy.但是,在生产中,在罕见的压力情况下,您不希望您的计时器因为系统繁忙而“漂移”。

You can either use Timer class from java.util or another way, which is more complicated, is with Threads.您可以使用java.utilTimer类,也可以使用其他更复杂的方法,即使用 Threads。 Timer also has thread action, but it's pretty easy to understand to use it. Timer 也有线程动作,但使用起来很容易理解。

For creating a simple timer as you explained as per your need , it is very easy to write a code for that.为了根据您的需要创建一个简单的计时器,为此编写代码非常容易。 I have written the below code for your reference.我已经编写了以下代码供您参考。 If you wish you can enhance it.如果你愿意,你可以加强它。

import java.util.concurrent.TimeUnit;导入 java.util.concurrent.TimeUnit; public class PerfectTimer {公共类 PerfectTimer {

public static void main(String[] args) throws InterruptedException 
{
    boolean x=true;
    long displayMinutes=0;
    long starttime=System.currentTimeMillis();
    System.out.println("Timer:");
    while(x)
    {
        TimeUnit.SECONDS.sleep(1);
        long timepassed=System.currentTimeMillis()-starttime;
        long secondspassed=timepassed/1000;
        if(secondspassed==60)
        {
            secondspassed=0;
            starttime=System.currentTimeMillis();
        }
        if((secondspassed%60)==0)
        displayMinutes++;

    System.out.println(displayMinutes+"::"+secondspassed);
    }

}

} }

if you want to update something in the main thread (like UI components) better to use Handler如果您想更新主线程中的某些内容(例如 UI 组件),最好使用 Handler

        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                //do something
            }
        }, 20);

20 - the delay In MS to do something. 20 - 延迟在MS做某事。 and run it in a loop.并循环运行。

I have created a Timer that has everything you might need in it.我创建了一个计时器,其中包含您可能需要的一切。

I even documented it!我什至记录了它!

And I also compiled it for faster usage.而且我还编译了它以加快使用速度。

Here's an example:这是一个例子:

//...
  //For demo only!
  public static void main(String[]a){
    Timer timer=new Timer();
    timer.setWatcher(new Timer.TimerWatcher(){
      public void hasStopped(boolean stopped){
        System.out.print(stopped+"     | ");
      }
      public void timeElapsed(long nano, long millis, long seconds){
        System.out.print(nano+", ");
        System.out.print(millis+", ");
        System.out.print(seconds+" | ");
      }
      public void timeLeft(long timeLeft){
        System.out.print(timeLeft+"\r");
      }
    });
    //Block the thread for 5 seconds!
    timer.stopAfter(5, Timer.seconds); //You can replace this with Integer.MAX_VALUE. 
    //So that our watcher won't go to waste.
    System.out.println();
  }
//...

This is not for promotion, made this to help people not waste their time in coding classes themselves!这不是为了推广,这样做是为了帮助人们不要在自己的编码课程上浪费时间!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM