安卓倒计时利器: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实现onTick和onFinish这两个抽象方法。
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%的场景足够用了。缺点也有:无暂停接口。如果需要暂停/恢复可以考虑结合协程封装。