安卓倒计时利器:CountDownTimer的使用

Quibbler 1月前 182

安卓倒计时利器:CountDownTimer的使用


        CountDownTimer是Android框架中自带中的一个类,用于实现倒计时功能。通过CountDownTimer类,可以创建一个倒计时器,指定总倒计时时间以及每次倒计时的间隔时间。一旦倒计时开始,CountDownTimer会在指定的间隔时间内执行操作,直到倒计时结束。


        CountDownTimer是一个抽象类:CountDownTimer(long millisInFuture, long countDownInterval),millisInFuture: 表示总的倒计时时间,以毫秒为单位。在倒计时结束之前,倒计时器将一直执行。countDownInterval: 表示倒计时的间隔时间,以毫秒为单位。每隔这个时间间隔,onTick()方法将会被调用一次。

    public abstract class CountDownTimer {
        private final long mMillisInFuture;
        private final long mCountdownInterval;
        private long mStopTimeInFuture;
 
        private boolean mCancelled = false;
    
        public CountDownTimer(long millisInFuture, long countDownInterval) {
            mMillisInFuture = millisInFuture;
            mCountdownInterval = countDownInterval;
        }
    
        public synchronized final void cancel() {
            mCancelled = true;
            mHandler.removeMessages(MSG);
        }
    
        public synchronized final CountDownTimer start() {
            mCancelled = false;
            if (mMillisInFuture <= 0) {
                onFinish();
                return this;
            }
            mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
            mHandler.sendMessage(mHandler.obtainMessage(MSG));
            return this;
        }    
        ...
    }

        包装了两个抽象方法onTick()onFinish(),通常在使用的时候继承自CountDownTimer实现onTickonFinish这两个抽象方法。

    public abstract class CountDownTimer {
        ...
        public abstract void onTick(long millisUntilFinished);
        public abstract void onFinish();
        ...
    }

        onTick(long millisUntilFinished):在每次倒计时间隔结束时调用,用于执行更新UI等操作。millisUntilFinished: 表示距离倒计时结束还有多少时间,以毫秒为单位。

        onFinish():在倒计时结束时调用,用于执行最终的操作。

        start():启动倒计时器,开始执行倒计时。

        cancel():取消倒计时器,停止倒计时的执行。


        CountDownTimer是基于Handler实现的,内部封装了Handler,这里使用默认的无参构造方式创建Handler

    @Deprecated
    public Handler() {
        this(null, false);
    }

        在之前的创建Handler的几种方法一文中,我们可以知道,默认用当前线程的Looper创建Handler,一般为主线程,如果在没有Looper的线程中创建Handler则会抛出异常。

    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = false;
    }

        无需自己切线程,回调运行在创建CountDownTimer对象的线程上,一般为主线程,也可能是HandlerThread等其它带Looper的子线程中。

    public abstract class CountDownTimer {
        .
        // 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);
                    }
                }
            }
        };
    }

        创建多个CountDownTimer时每个实例拥有独立的锁、独立的Handler消息队列,彼此完全并行,不会出现锁等待。


        CountDownTimer的优点是官方、简洁、内部维护Handler实现倒计时,对于90%的场景足够用了。缺点也有:无暂停接口。如果需要暂停/恢复可以考虑结合协程封装。



不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com