转自: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