CountDownTimer的使用以及解决Cancel无效的问题

来源:互联网 发布:php接口文档生成工具 编辑:程序博客网 时间:2024/05/17 03:33

在做项目的时候,需要一个倒计时的功能。查阅资料,Android提供了一个倒计时的功能 CountDownTimer。

官方提供的用法如下:

 * 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> *

创建CountDownTimer实例之后,必须通过start()函数将计时器开启,才能保证CountDownTimer运行。CountDownTimer还提供了cancel()方法,可以将计时器取消。

在使用CountDownTimer时,必须实现两个方法:onTick() 和 onFinish()。
在onTick(long millisUntilFinished) 中的参数millisUntilFinished是倒计时的剩余时间。在倒计时结束后会调用onFinish,倒计时结束后需要执行的操作可以写在onFinish中。

CountDownTimer(30000, 1000)中的30000,表示倒计时时间为30秒,1000表示每隔1秒钟调用一次onTick方法。

在使用过程中发现,在一个activity或者fragment中开启了计时器,如果倒计时没有完成即退出activity或者fragment,此时onTick仍然会继续执行,当执行到mTextField.setText()时,mTextField为null,导致程序crash。因此需要在onTick中进行非空判断。

如果是在Fragment中:

if(getActivity()!=null){   //todo }

如果是在Activity中:

if(!activity.isFinishing()){    //todo}

但是我们不希望在fragment或activity退出之后仍然调用onTick,即使已经做了非空判断。
我们希望在退出之后CountDownTimer也随之停止,因此在onTick中,当getActivity()==null或者activity.isFinishing()==true的时候,可以使用cancel方法取消掉计时器。

But!!!
经过实验发现,cancel在onTick中调用,是无法成功取消计时器的。
调用cancel之后,仍然会每隔固定时间调用onTick方法。
然而,在5.0及以上的系统中,cancel方法就可以起到作用。对比CountDownTimer的源码发现,在5.0中,增加了一个字段

  /**  * boolean representing if the timer was cancelled  */    private boolean mCancelled = false;

通过mCancelled 标识当前计时器是否取消。
然后在handleMessage()中首先对mCancelled进行判断:

// handles counting down    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            synchronized (CountDownTimer.this) {                if (mCancelled) { //**Attention!!!**                    return;                }                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);                }            }        }    };

因此,如果想在onTick中调用cancel方法取消计时器,可以自定义一个CountDownTimerUtil,将5.0以上的CountDownTimer源码复制到CountDownTimerUtil即可。

5.0 CountDownTimer 源码:
http://download.csdn.net/detail/liuweiballack/8831309

4.4 CountDownTimer源码:
http://download.csdn.net/detail/liuweiballack/8831333

2 0
原创粉丝点击