Handler机制应用之CountDownTimer篇

关于Handler的内部原理及实现可以查看——Handler机制源码之路。

CountDownTimer 是系统提供的一个倒计时类。其内部就是使用了 Handler 封装的。

1. 用法

先来看一下如何使用。

// 源码注释
new CountDownTimer(30000, 1000) {

      public void onTick(long millisUntilFinished) {
         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
     }
     
      public void onFinish() {
           mTextField.setText("done!");
     }
}.start();

可以看到,直接 new 一个 CountDownTimer 实例, 传入两个参数, 实现两个抽象方法onTick(long)onFinish(), 然后 start()

2. 源码

接下来通过源码+注释说明参数作用。

2.1 构造方法

/**
 * @param millisInFuture The number of millis in the future from the call
 *   to {@link #start()} until the countdown is done and {@link #onFinish()}
 *   is called.
 * @param countDownInterval The interval along the way to receive
 *   {@link #onTick(long)} callbacks.
 *   参数1 millisInfuture:这个参数代表你要倒计时的整体毫秒值,当start()开始执行时开始倒计时,当倒计时结束时回调onFinish()方法
 *   参数2 countDownInterval: 代表每次onTick(long)回调的时机,每countDownInterval差值回调一次
 */
public CountDownTimer(long millisInFuture, long countDownInterval) {
    mMillisInFuture = millisInFuture;
    mCountdownInterval = countDownInterval;
}

2.2 抽象方法

可以看到 onFinish()onTick(long) 方法为抽象方法,需要子类实现。

/**
 * Callback fired on regular interval.
 * @param millisUntilFinished The amount of time until finished.
 */
public abstract void onTick(long millisUntilFinished);

/**
 * Callback fired when the time is up.
 */
public abstract void onFinish();

2.3 start() 方法

/**
 * Start the countdown.
 */
public synchronized final CountDownTimer start() {
    mCancelled = false;
    if (mMillisInFuture <= 0) {// 如果开始的时候倒计时总时长未设置或为负数,直接结束。
        onFinish();
        return this;
    }
    mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;// 当前时间+总时间,等于要停止的实际时间
    // 通过Handler 发送消息,然后在Handler中真正开始计时
    mHandler.sendMessage(mHandler.obtainMessage(MSG));
    return this;
}

2.4 Handler 部分

// handles counting down
// 内部成员变量直接实例化,说明一个CountDownTimer对应一个Handler
private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {

        synchronized (CountDownTimer.this) {// 这个锁我不知道为什么要加,我的理解在这个方法中一定是回调的同线程的Handler,Handler也没有声明成异步Handler,所以一定是按顺序回调
            if (mCancelled) {
                return;
            }

            final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();// 要停止的实际时间-当前时间,表示开始倒计时的总时长

            if (millisLeft <= 0) {
                onFinish();
            } else {
                long lastTickStart = SystemClock.elapsedRealtime();// 上次回调时间
                onTick(millisLeft);
                long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;// 回调执行的时间
                long delay;
                if (millisLeft < mCountdownInterval) {// 需要倒计时的时间小于单次间隔
                    delay = millisLeft - lastTickDuration;
                    // 如果执行时间过长,会导致计时不准,这时直接进入下一次倒计时
                    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);
            }
        }
    }
};

2.5 cancel() 方法

public synchronized final void cancel() {
    mCancelled = true;
    mHandler.removeMessages(MSG);
}

3. 总结

很简单的一个类,就是使用Handler封装的倒计时工具。需要注意的就是

  • CountDownTimer 创建的时候,一定要保证所在线程的 Looper 已经开启。
  • Activity 注销时,记着取消定时器。
  • 定时器中不要留存 Activity 的强引用。

你可能感兴趣的:(Handler机制应用之CountDownTimer篇)