CountDownTimer 解决 Cancel无效的问题

来源:互联网 发布:淘宝网夏秋棉麻连衣裙 编辑:程序博客网 时间:2024/06/06 13:57

转自:http://blog.csdn.net/liuweiballack/article/details/46605787

在做项目的时候,需要一个倒计时的功能。查阅资料,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中

但是我们不希望在fragment或activity退出之后仍然调用onTick,即使已经做了非空判断。 

我们希望在退出之后

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

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

1 0
原创粉丝点击