Улучшить точность моего таймера - PullRequest
1 голос
/ 03 марта 2011

Ниже у меня есть тема, которая обновляет метку '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, когда я пытаюсь обновить метку таймера - Вот мой код -

Здесь я создаю свой экземплярlabel -

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 ]

3 голосов
/ 03 марта 2011

Попробуйте использовать ScheduledExecutorService.scheduleAtFixedRate , который будет выполнять вашу задачу через фиксированные промежутки времени, независимо от того, сколько времени ушло на выполнение предыдущей задачи.

3 голосов
/ 03 марта 2011
Thread.sleep(1000);

Переводит поток в состояние сна на не менее 1 с, после чего он возвращается в состояние готовности к работе, которое не гарантирует немедленного запуска, просто "готово к запланировано запустить в любое время в будущем ". Это зависит от планировщика потока, когда он его запустит. Вы можете, например, проверить системное время, чтобы действительно знать, сколько времени прошло ...

2 голосов
/ 03 марта 2011

Если вам нужен таймер, предложите использовать Таймер . Также предложите, чтобы, если вы хотите сохранить часы, вы не пытались сделать это самостоятельно, а вместо этого взяли образцы системных часов. Возможно, вы хотите, чтобы образец currentTimeMillis()

1 голос
/ 03 марта 2011

Есть две вещи, которые могут помочь ... Во-первых, функция incrementTimer () вызывает convertValToTimerString (). Как вы упомянули, это приведет к некоторому замедлению. Это не будет много, но со временем эта задержка будет накапливаться. Вы остаетесь в текущем потоке выполнения. Решением будет использование схемы модель-представление-контроллер. Модель будет вашим полем "val". Вид это метка. Контроллер будет тогда потоком, который обновляет это поле раз в секунду. Отделяя обновления модели от выполнения кода, необходимого для их просмотра, поток обновления может работать без помех. Конечно, вам все еще нужен способ регулярно обновлять текст на этикетке в зависимости от значения вашей модели. Об этом может позаботиться отдельный поток.

Итак, что мы имеем:

  • Модель (в вашем случае, просто одно значение)
  • Контроллер (неинтерактивный поток, обновляющий модель)
  • Вид (метка)
  • Поток, который обновляет представление

Для контроллера было бы лучше использовать Timer, чем использовать Runnable, который вызывает Thread.sleep (), как предложил andersoj. Вам нужно будет реализовать TimerTask. Существует разница между планированием с фиксированной задержкой и планированием с фиксированной скоростью. Фиксированная ставка предпочтительнее для такой задачи, как ваша, где средняя согласованность важнее регулярности. Имейте в виду, что если вы используете таймер, то приведенная выше схема модель-представление-контроллер немного излишня. Вы, вероятно, сможете включить обновление метки в метод запуска TimerTask. Но только потому, что это произойдет достаточно быстро. Если обновление вашего представления требует больше времени (как это может быть в случае сочетания быстрых обновлений с интенсивным рисованием), шаблон MVC обеспечит надлежащее разделение проблем и сохранит актуальность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...