移动开发进阶

Android 中简单实现倒计时功能

2019-07-30  本文已影响0人  Jboob

在Android 中倒计时功能是比较普遍使用的一个功能,比如手机验证码,计时执行命令等。实现方式有Handler、Thread 等,但是实现起来都比较复杂,过于麻烦,需要自己去写很多代码。今天讲讲在Android中如何用CountDownTimer 非常简单的实现倒计时功能。

先看看CountDownTimer 类源码,我们先来熟悉它的构造,再动手。
CountDownTimer 实现倒计时功能的机制也是用Handler 消息控制,只是它帮我们已经封装好了,我们可以直接实现类提供的方法就可以写自己的业务逻辑了。

/**
 * Schedule a countdown until a time in the future, with
 * regular notifications on intervals along the way.
 *
 * Example of showing a 30 second countdown in a text field:
 *
 * <pre class="prettyprint">
 * new CountDownTimer(30000, 1000) {
 *
 *     public void onTick(long millisUntilFinished) {
 *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
 *     }
 *
 *     public void onFinish() {
 *         mTextField.setText("done!");
 *     }
 *  }.start();
 * </pre>
 *
 * The calls to {@link #onTick(long)} are synchronized to this object so that
 * one call to {@link #onTick(long)} won't ever occur before the previous
 * callback is complete.  This is only relevant when the implementation of
 * {@link #onTick(long)} takes an amount of time to execute that is significant
 * compared to the countdown interval.
 */

大致描述是 设置一个倒计时时间,直到完成一个时间段的计时,并且会时时更新时间的变化,举了一个30秒倒计时的例子如下

new CountDownTimer(30000, 1000) {

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

      public void onFinish() {
          mTextField.setText("done!");
      }
   }.start();

我们从这个例子中可以看出,他有一个构造方法,传入了两个参数。

 /**
     * @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.
     */
    public CountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

第一个参数传入设置倒计时的总时间,第二个参数传入每隔多少毫秒执行一次,注意这里传入的两个时间参数的单位都是毫秒。如我要定义一个一分的倒计时,每隔一秒执行一次,传参时就应该是 new CountDownTimer(60000, 1000)。

下面看看提供的这几个方法。

 /**
     * Cancel the countdown.
     */
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    /**
     * Start the countdown.
     */
    public synchronized final CountDownTimer start() {
        mCancelled = false;
        if (mMillisInFuture <= 0) {
            onFinish();
            return this;
        }
        mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }


    /**
     * 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();

cancel() 从字面上也理解到,它就是取消倒计时的意思.通过Handler removeMessages 取消正在执行的倒计时任务。
start() 开始执行倒计时。通过Handler sendMessage 发送消息并开始执行倒计时任务。
onTick() 倒计时更新。这里可以得到距离完成倒计时还剩多少时间。
onFinish() 倒计时完成后的回调。

我们再来看看Handler 实现部分

// 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() 方法更新当前倒计时时间,当mStopTimeInFuture 减去 SystemClock.elapsedRealtime()(boot 以来经过的毫秒数)小于等于 0 时 ,则调用 onFinish()。

下面我们简单写一个实现倒计时的demo
为了代码维护和重用,我这里写一个公共的倒计时 CommonCountDownTimer 类,代码如下:

import android.os.CountDownTimer;
/**
 * 公共倒计时类
 */
public class CommonCountDownTimer extends CountDownTimer {

    private OnCountDownTimerListener countDownTimerListener;

    public void setCountDownTimerListener(OnCountDownTimerListener listener) {
        this.countDownTimerListener = listener;
    }

    /**
     * @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.
     */
    public CommonCountDownTimer(long millisInFuture, long countDownInterval) {
        super(millisInFuture, countDownInterval);
    }

    @Override
    public void onTick(long millisUntilFinished) {
        if (null != countDownTimerListener) {
            countDownTimerListener.onTick(millisUntilFinished);
        }
    }

    @Override
    public void onFinish() {
        if (null != countDownTimerListener){
            countDownTimerListener.onFinish();
        }
    }


    public interface OnCountDownTimerListener {
        /**
         * 更新倒计时时间
         *
         * @param millisUntilFinished
         */
        void onTick(long millisUntilFinished);

        /**
         * 完成倒计时
         */
        void onFinish();
    }
}

这里的CommonCountDownTimer 类继承了 android.os.CountDownTimer 类,我定义了一个 OnCountDownTimerListener 接口主要来监听 onTick(long millisUntilFinished) 和 onFinish() ,这样可以把业务逻辑分开来处理。

开始使用

private void initCountDownTimer() {
        mCountDownTimer = new CommonCountDownTimer(60000, 1000);
        mCountDownTimer.setCountDownTimerListener(new CommonCountDownTimer.OnCountDownTimerListener() {
            @Override
            public void onTick(long millisUntilFinished) {
                tv_time.setText("倒计时:" + millisUntilFinished / 1000);
            }

            @Override
            public void onFinish() {
                tv_time.setText("倒计时: 00");
            }
        });
    }

就是这么简单,主要需要理解 CountDownTimer 这个类,理解了之后就可以根据自己的业务场景灵活使用了。
由于本人很菜,有些地方认识理解不对的地方欢迎,谢谢大家指正。
觉得还行的可以关注公众号好 ProgrammerRan 查看更多内容。

ProgrammerRan
上一篇下一篇

猜你喜欢

热点阅读