提高我的计时器线程的准确性

时间:2011-03-03 16:07:29

标签: java java-me

下面我有一个每秒更新一次'clock'标签的线程。一旦线程达到600(10分钟),计时器就会停止。线程似乎每分钟大约需要五秒钟。因此,当val = 60时,实际上可能已经过了65秒。我正在使用midp所以我不认为我可以引入任何api来帮助我完成这项任务。如何提高课堂以下的准确度?我认为减慢它的方法是convertValToTimerString方法,有没有更好的方法将当前定时器val转换为分钟:秒格式而不使用java格式化程序apis?

谢谢,

public class LabelTimerUpdaterThread implements Runnable{

    public static int val = 0;
    private int minuteValueInt = 0;
    private int secondValueInt = 0;
    private int tempSecondValueInt;
    public boolean isRunning = true;

    public LabelTimerUpdaterThread(){

    }

    public void run() {
        while(isRunning){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            val += 1;


            incrementTimer();

            if(val == 600){
                break;
            }
        }
    }

    private void incrementTimer(){
        Screen.timerLabel.setText(convertValToTimerString(val));
    }

    private String convertValToTimerString(int val){

        String minuteValString = "";
        String secondValString = "";

        if(val < 10){
            minuteValString = "00";
            secondValString = "0"+String.valueOf(val);
            return minuteValString+":"+secondValString;
        }

        if(val < 60){
            minuteValString = "00";
            secondValString = String.valueOf(val);
            return minuteValString+":"+secondValString;
        }

        if(val % 60 == 0){
            ++minuteValueInt;
        }

            if(minuteValueInt < 10){
                minuteValString = "0"+String.valueOf(minuteValueInt);
                int secondVal = val % 60;
                if(secondVal < 10){
                    return minuteValString+":0"+String.valueOf(secondVal);
                }
                else {
                    return minuteValString+":"+String.valueOf(secondVal);
                }
            }

        return "10:00";
    }

    public void stopThread(){
        this.isRunning = false;
    }

好的,现在我在尝试使用我的计时器标签时收到IllegalStateException -  这是我的代码 -

我在这里实例化我的标签 -

timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png"));

UpdateValTimer timer = new UpdateValTimer(th);
timer.startTimer();

此类创建计时器类并创建将更新计时器标签的类。

public class UpdateValTimer {

    private Timer timer;
    private int val = 0;
    private UpdateView uv;
    private final CustomLabelField customLabelField;

    public UpdateValTimer(CustomLabelField field) {
        this.customLabelField = field;
    }

    public void startTimer(){
        timer = new Timer();
        uv = new UpdateView(customLabelField);
        Thread t = new Thread(uv);
        t.start();

        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                ++val;      
            }
        }, 1000, 1000);
    }
}

此类更新计时器标签 -     公共类UpdateView实现了Runnable {

    private int val = 0;
    private int minuteValueInt = 0;
    private final CustomLabelField timerLabel;

    public UpdateView(CustomLabelField timerLabel) {
        this.timerLabel = timerLabel;
    }

    public void run() {
        while(true){
            this.timerLabel.setText(convertValToTimerString(this.val));
        }
    }

     private String convertValToTimerString(int val){

            String minuteValString = "";
            String secondValString = "";

            if(val < 10){
                minuteValString = "00";
                secondValString = "0"+String.valueOf(val);
                return minuteValString+":"+secondValString;
            }

            if(val < 60){
                minuteValString = "00";
                secondValString = String.valueOf(val);
                return minuteValString+":"+secondValString;
            }

            if(val % 60 == 0){
                ++minuteValueInt;
            }

                if(minuteValueInt < 10){
                    minuteValString = "0"+String.valueOf(minuteValueInt);
                    int secondVal = val % 60;
                    if(secondVal < 10){
                        return minuteValString+":0"+String.valueOf(secondVal);
                    }
                    else {
                        return minuteValString+":"+String.valueOf(secondVal);
                    }
                }

            return "10:00";
        }

}

感谢您的帮助

经过一些初步测试后,这段代码似乎运行正常。

感谢大家的帮助。

欢迎任何关于我可以做得更好的评论。

public class UpdateValTimer{

    private int minuteValueInt = 0;
    private Timer timer;
    private int val = 0;
    private UpdateView uv;
    private CustomLabelField customLabelField;

    public UpdateValTimer(CustomLabelField field) {
        this.customLabelField = field;
    }

    public void startTimer(){
        timer = new Timer();
            uv = new UpdateView(customLabelField);
            Thread t = new Thread(uv);
            t.start();

        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {             
                ++val;      
                uv.setVal(convertValToTimerString(val));
            }
        }, 1000, 1000);


    }

     private String convertValToTimerString(int val){

            String minuteValString = "";
            String secondValString = "";

            if(val < 10){
                minuteValString = "00";
                secondValString = "0"+String.valueOf(val);
                return minuteValString+":"+secondValString;
            }

            if(val < 60){
                minuteValString = "00";
                secondValString = String.valueOf(val);
                return minuteValString+":"+secondValString;
            }

            if(val % 60 == 0){
                ++minuteValueInt;
            }

                if(minuteValueInt < 10){
                    minuteValString = "0"+String.valueOf(minuteValueInt);
                    int secondVal = val % 60;
                    if(secondVal < 10){
                        return minuteValString+":0"+String.valueOf(secondVal);
                    }
                    else {
                        return minuteValString+":"+String.valueOf(secondVal);
                    }
                }

            return "10:00";
        }
}


public class UpdateView implements Runnable{

    private String timeElapsedCounter;
    private final CustomLabelField timerLabel;

    public UpdateView(CustomLabelField timerLabel) {
        this.timerLabel = timerLabel;
    }

    public void setVal(String timeElapsedCounter){
        this.timeElapsedCounter = timeElapsedCounter;
    }

    public void run() {

        while(true){
        synchronized(Application.getEventLock()){
            timerLabel.setText(this.timeElapsedCounter);
        }
        }
    }

}


        timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png"));

        UpdateValTimer timer = new UpdateValTimer(timerLabel);
        timer.startTimer();

4 个答案:

答案 0 :(得分:3)

Thread.sleep(1000);

将线程置于至少 1s的休眠状态,然后它回到准备运行状态,这不能保证它会立即运行,它只是“准备就绪”计划在将来的任何时间运行“。它将在运行它时由线程调度程序决定。例如,您可能希望检查系统时间以确切知道已经过了多长时间......

答案 1 :(得分:3)

尝试使用 ScheduledExecutorService.scheduleAtFixedRate ,它会以固定的时间间隔执行您的任务,无论上一个任务需要多长时间才能完成。

答案 2 :(得分:2)

如果您需要计时器,建议您使用Timer。还建议如果你想保持一个时钟,你不要自己尝试这样做,而是采样系统时钟。也许您想要的是样本currentTimeMillis()

答案 3 :(得分:1)

有两件事可能会有所帮助......首先,函数incrementTimer()调用convertValToTimerString()。正如你所提到的,这会引入一些减速。它不会太多,但随着时间的推移,这种延迟将会累积。你将留在当前的执行线程中。解决方案是使用模型 - 视图 - 控制器方案。该模型将是您的“val”字段。视图是标签。然后控制器将是每秒更新一次该字段的线程。通过将模型更新与查看它们所需的代码执行分开,更新线程可以不受干扰地运行。当然,您仍然需要根据模型的值定期更新标签上的文本。一个单独的线程可以解决这个问题。

所以我们拥有的是:

  • 模型(在您的情况下,只是一个值)
  • 控制器(更新模型的非交互式线程)
  • 视图(标签)
  • 更新视图的主题

对于控制器,使用Timer确实是一个更好的选择,而不是像andersoj建议的那样使用调用Thread.sleep()的Runnable。你需要实现TimerTask。固定延迟的调度和固定速率的调度之间存在差异。对于像您这样的任务,固定费率是可取的,其中平均一致性比规律性更重要。请记住,如果您使用Timer,我建议的上述模型 - 视图 - 控制器方案有点矫枉过正。您可能能够将标签更新合并到TimerTask的run方法中。但只是因为它会发生得足够快。如果您的视图更新需要更多时间(对于快速更新和重绘图的组合可能就是这种情况),MVC模式将提供正确的关注点分离并使事情保持不变。