Android: CountDownTimer пропускает последний onTick ()! - PullRequest
44 голосов
/ 14 января 2012

код:

public class SMH extends Activity {  

    public void onCreate(Bundle b) {  
        super.onCreate(b);  
        setContentView(R.layout.main);  

        TextView tv = (TextView) findViewById(R.id.tv);  

        new CountDownTimer(10000, 2000) {  
            public void onTick(long m) {  
               long sec = m/1000+1;  
               tv.append(sec+" seconds remain\n");  
            }  
            public void onFinish() {  
               tv.append("Done!");  
            }  
        }.start();  
   }

Выход:
10 секунд осталось
8 секунд осталось
6 секунд осталось
4 секунды осталось
Готово!

Проблема:

Как мне заставить его показать " 2 секунды осталось "? Истекшее время действительно составляет 10 секунд, но последний onTick () никогда не происходит. Если я изменю второй параметр с 2000 на 1000, то это будет вывод:

10 секунд осталось
9 секунд осталось
8 секунд осталось
7 секунд осталось
6 секунд осталось
5 секунд осталось
4 секунды осталось
3 секунды осталось
2 секунды осталось
Готово!

Итак, вы видите, что, похоже, пропускает последний вызов onTick (). И, кстати, XML-файл - это по умолчанию main.xml по умолчанию с TextView, которому присвоен идентификатор tv , а для текста установлено значение "".

Ответы [ 12 ]

0 голосов
/ 11 июня 2017

Я также столкнулся с той же проблемой с CountDownTimer, и я попробовал разные подходы.Поэтому одним из самых простых способов является решение, предоставленное @Nantoca - он предлагает удвоить частоту с 1000 до 500 мс.Но мне не нравится это решение, потому что оно делает больше работы, которая потребляет некоторый дополнительный ресурс батареи.

Поэтому я решил использовать soultion @ ocanal и написать свой собственный простой CustomCountDownTimer.

НоЯ нашел пару недостатков в его коде:

  1. Это немного неэффективно (создание второго обработчика для публикации результатов)

  2. Сначала начинает публиковатьрезультат с задержкой.(Вам нужно сделать метод post() вместо postDelayed() при первой инициализации)

  3. странный вид.Методы с заглавной буквой, статус вместо классического isCanceled boolean и некоторые другие.

Итак, я немного убрал его, и вот более распространенная версия его подхода:

private class CustomCountDownTimer {

    private Handler mHandler;
    private long millisUntilFinished;
    private long countDownInterval;
    private boolean isCanceled = false;

    public CustomCountDownTimer(long millisUntilFinished, long countDownInterval) {
        this.millisUntilFinished = millisUntilFinished;
        this.countDownInterval = countDownInterval;
        mHandler = new Handler();
    }

    public synchronized void cancel() {
        isCanceled = true;
        mHandler.removeCallbacksAndMessages(null);
    }

    public long getRemainingTime() {
        return millisUntilFinished;
    }

    public void start() {

        final Runnable counter = new Runnable() {

            public void run() {

                if (isCanceled) {
                    publishUpdate(0);
                } else {

                    //time is out
                    if(millisUntilFinished <= 0){
                        publishUpdate(0);
                        return;
                    }

                    //update UI:
                    publishUpdate(millisUntilFinished);

                    millisUntilFinished -= countDownInterval;
                    mHandler.postDelayed(this, countDownInterval);
                }
            }
        };

        mHandler.post(counter);
    }
}
0 голосов
/ 14 января 2012

Вы неправильно рассчитываете оставшееся время. Обратный вызов получает количество миллисекунд до завершения задачи.

public void onTick(long m) {  
    long sec = m/1000+1;  
    tv.append(sec+" seconds remain\n");  
}  

должно быть

public void onTick(long m) {  
    long sec = m/1000;  
    tv.append(sec+" seconds remain\n");  
}

Я никогда не использовал этот класс сам, но похоже, что вы не получите обратный вызов в тот момент, когда он начинается, поэтому кажется, что вы пропустили запись. например 10000 мс, 1000 мс за тик вы получите в общей сложности 9 обратных вызовов обновления, а не 10–9000, 8000, 7000, 6000, 5000, 4000, 3000, 2000, 1000, финиш.

...