Android CountDownTimer Case Summary
- 2021-12-13 16:54:01
- OfStack
1. Overview
Countdown functions are often used in projects, such as time-limited snapping, mobile phone obtaining verification code and so on. The google official also helped us package a class: CountDownTimer, which made our development more convenient;
2. API
CountDownTimer is an abstract class with two abstract methods, and its API is very simple
public abstract void onTick(long millisUntilFinished);// This is a callback every time at a specified time interval, millisUntilFinished Remaining time in milliseconds
public abstract void onFinish();// This is the callback at the end of the countdown
When you use it, you only need to
new CountDownTimer(long millisInFuture, long countDownInterval)
//millisInFuture: Total length of countdown
//countDownInterval : The interval between each time The units are all milliseconds
3. Basic usage
We look at the countdown of SMS verification code, click to get the verification code, and the countdown of 60s cannot be clicked
new CountDownTimer(60 * 1000, 1000) {
@Override
public void onFinish() {
if (tvCode != null) {
tvCode.setText(" Retrieve ");
tvCodeWr.setTextColor(Color.parseColor("#E94715"));
tvCode.setClickable(true);
tvCode.setEnabled(true);
}
cancel();
}
@Override
public void onTick(long millisUntilFinished) {
if (tvCode != null) {
tvCode.setClickable(false);
tvCode.setEnabled(false);
tvCode.setText(millisUntilFinished / 1000 + "s");
tvCode.setTextColor(Color.parseColor("#999999"));
}
}
}.start();
Click on the button to get the verification code successfully, and then you can perform the above operations. The last 1 must be start, otherwise it will not be executed
4. Use caution
CountDownTimer is very simple to use, but there are many pits, so we should pay attention to avoid stepping on pits.
1. Null pointer: If cancle method is not called when activity or fragment is closed and destroyed, its onTick method will continue to execute. At this time, UI controls are all empty, so it is easy to null pointer if you don't pay attention to judgment
2. The time is not too accurate:
When we look at the source code of CountDownTimer, we can see that when executing the method of onTick, the time consumed when the program is executed here is subtracted from the source code of google, and we can see the rigor of google code here
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
onFinish();
} else if (millisLeft < mCountdownInterval) {
// no tick, just delay until done
sendMessageDelayed(obtainMessage(MSG), millisLeft);
}
Therefore, the countdown time from 1 is 59, which can be solved by adding a little time to the constructor. For example:
new CountDownTimer(60 * 1000+300, 1000)
3. Memory leak problem
First, let's look at the source code. The core code is as follows
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);
}
}
}
};
It can be seen that the principle of CountDownTimer still uses Handler. Therefore, it is easy to cause memory leakage problems, When Activity or Fragment is closed and the countdown is not over, it will be executed directly in the background. Most of the time, we will update UI with countdown, and the controls all hold references to activity. If they are not released for a long time, it will cause memory leakage and even cause the null pointer problem mentioned in 1, so 1 should call cancle method when activity or fragment is destroyed.
I encapsulated this myself and wrote it as a tool class for reference:
public class TimeUtils {
private String color;// You can modify the text color here
WeakReference<TextView> tvCodeWr;// Control soft reference to prevent memory leakage
private CountDownTimer timer;
public TimeUtils(TextView tvCode, String color) {
super();
this.tvCodeWr = new WeakReference(tvCode);
this.color = color;
}
// This is the countdown execution method
public void RunTimer() {
timer = new CountDownTimer(60 * 1000 - 1, 1000) {
@Override
public void onFinish() {
if (tvCodeWr.get() != null) {
tvCodeWr.get().setText(" Retrieve ");
tvCodeWr.get().setTextColor(Color.parseColor(color));
tvCodeWr.get().setClickable(true);
tvCodeWr.get().setEnabled(true);
}
cancel();
}
@Override
public void onTick(long millisUntilFinished) {
if (tvCodeWr.get() != null) {
tvCodeWr.get().setClickable(false);
tvCodeWr.get().setEnabled(false);
tvCodeWr.get().setText(millisUntilFinished / 1000 + "s");
tvCodeWr.get().setTextColor(Color.parseColor("#999999"));
}
}
}.start();
}
// This method can be used in activity Or fragment Called when destroyed to prevent memory leakage
public void cancle() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
}