1、API

1
CountDownTimer (long millisInFuture, long countDownInterval)

参数1,设置倒计时的总时间(毫秒)
参数2,设置每次减去多少毫秒

2、基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private Button btn;// 略写初始化

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btn.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
timer.start();
}
});
}

private CountDownTimer timer = new CountDownTimer(60000, 1000) {

@Override
public void onTick(long millisUntilFinished) {
btn.setText((millisUntilFinished / 1000) + "秒后可重发");
}

@Override
public void onFinish() {
btn.setText("重新获取");
}
};

@Override
protected void onDestroy() {
super.onDestroy();
if (timer != null){
timer.cancel();
}
}

3、存在的问题

注意onDestroy() ,不然会存在内存泄漏的问题,源码很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package android.os;

/**
* ...
*/
public abstract class CountDownTimer {
/**
* ...
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}

/**
* 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;
}

.......

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 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);
}
}
}
};
}

从源码中可以看出,CountDownTimer的内部实现是采用Handler机制,通过sendMessageDelayed延迟发送一条message到主线程的looper中,然后在自身中收到之后判断剩余时间,并发出相关回调,然后再次发出message的方式。
如果在Activity或者Fragment被回收时并未调用CountDownTimer的cancel()方法结束自己,这个时候CountDownTimer的Handler方法中如果判断到当前的时间未走完,那么会继续调用sendMessageDelayed(obtainMessage(MSG), delay);触发onTick(millisLeft);,当回调了Activity或者fragment中CountDownTimer的onTick方法时,Activity或者Fragment已经被系统回收,从而里面的变量被设置为null,再调用btn.setText((millisUntilFinished / 1000) + "秒后可重发");btn为空,也就空指针了,而CountDownTimer中的Handler方法还在继续执行,这一块空间始终无法被系统回收也就造成了内存泄漏问题。