倒计时器 CountDownTimer

倒计时器 CountDownTimer


一个非常简单易用的倒计时类,其实仍然是使用Handler来进行计时,不过封装好之后用起来方便多了。


一、10秒倒计时示例
    new CountDownTimer(10000, 1000) {
        @Override
        public void onTick(long l) {
            tvCountDown.setText(String.valueOf(l / 1000));
            Log.e(TAG, "CountDownTimer long l = " + l);
        }

        @Override
        public void onFinish() {
            Log.e(TAG, "CountDownTimer onFinish");
        }
    }.start();

其中第一个参数为倒计时的总时间,第二个参数为Tick间隔时间,单位均是毫秒。

二、 onTick回调方法

onTick(long l) 回调方法返回的时间通常不是整数时间,比如上面的例子传入了 100001000,返回的参数如下:

MainActivity: CountDownTimer long l = 9999
MainActivity: CountDownTimer long l = 8999
MainActivity: CountDownTimer long l = 7997
MainActivity: CountDownTimer long l = 6995
MainActivity: CountDownTimer long l = 5995
MainActivity: CountDownTimer long l = 4993
MainActivity: CountDownTimer long l = 3992
MainActivity: CountDownTimer long l = 2990
MainActivity: CountDownTimer long l = 1988
MainActivity: CountDownTimer onFinish

没有一个是1000的整数倍的,总是少几毫米至十几毫秒,甚至只返回了9个参数。返回1988之后,直接就onFinish()了。啊?为什么会这样?!于是去找了一下源码,核心代码如下:

// handles counting down
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        synchronized (CountDownTimer.this) {
            final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
            if (millisLeft <= 0) {
                onFinish();
            } else if (millisLeft < mCountdownInterval) {
                // no tick, just delay until done
                sendMessageDelayed(obtainMessage(MSG), millisLeft);
            } else {
                long lastTickStart = SystemClock.elapsedRealtime();
                onTick(millisLeft);
                // take into account user's onTick taking time to execute
                long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
                // special case: user's onTick took more than interval to
                // complete, skip to next interval
                while (delay < 0) delay += mCountdownInterval;
                sendMessageDelayed(obtainMessage(MSG), delay);
           }
        }
    }
};

其中 当millisLeft < mCountdownInterval时,就不再调用onTick方法了。然而,奇怪的是,我又找到了另一份源码,核心代码如下:

// handles counting down
private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {

        synchronized (CountDownTimer.this) {
            if (mCancelled) {
                return;
            }

            final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

            if (millisLeft <= 0) {
                onFinish();
            } else {
                long lastTickStart = SystemClock.elapsedRealtime();
                onTick(millisLeft);

                // take into account user's onTick taking time to execute
                long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
                long delay;

                if (millisLeft < mCountdownInterval) {
                    // just delay until done
                    delay = millisLeft - lastTickDuration;

                    // special case: user's onTick took more than interval to
                    // complete, trigger onFinish without delay
                    if (delay < 0) delay = 0;
                } else {
                    delay = mCountdownInterval - lastTickDuration;

                    // special case: user's onTick took more than interval to
                    // complete, skip to next interval
                    while (delay < 0) delay += mCountdownInterval;
                }

                sendMessageDelayed(obtainMessage(MSG), delay);
            }
        }
    }
};

按照上面这第二份源码,只要剩余时间大于零,应该就会回调onTick方法。于是我把这份源码拷贝到工程,打印出这份代码的onTick回调参数,如下:

MainActivity: CountDownTimer long l = 9999
MainActivity: CountDownTimer long l = 8998
MainActivity: CountDownTimer long l = 7996
MainActivity: CountDownTimer long l = 6993
MainActivity: CountDownTimer long l = 5991
MainActivity: CountDownTimer long l = 4989
MainActivity: CountDownTimer long l = 3987
MainActivity: CountDownTimer long l = 2985
MainActivity: CountDownTimer long l = 1983
MainActivity: CountDownTimer long l = 981
MainActivity: CountDownTimer onFinish

果然,onTick方法回调了十次,这样也比小于间隔时间就直接回调onFinish方法合理多了。

我查看了一下安卓的各版本源码,似乎api25及之前,都是用第一份源码 CountDownTimer源码1api26及之后,就改为了第二份源码CountDownTimer源码2

最后

用完之后,别忘了调用 cancle()方法。

猜你喜欢

转载自blog.csdn.net/chenrenxiang/article/details/80257745