最近两个月项目赶得紧,没有学习什么新技术,就是对基础进行了巩固。每个安卓项目中都少不了登录注册的模块,既然有注册,那么获取验证码的功能是少不了的(都是固定套路)。其实获取验证码实现倒数计时的这个功能很多人都做过,而且有好几种实现方式,比如(java自带的Timer,Thread+Handler,AlarmManager等);今天我就给大家送上android系统封装好的倒计时工具CountDownTimer,其实CountDownTimer内部也是通过Handler发延迟消息实现的;为了能适应项目的要求我对CountDownTimer进行了自己的二次封装。
下面就是我封装的工具类,有兴趣的可以拿去试试,具体的我都写了注释,这里我没有用泛型,一般的都是个Button,有可能为了扁平化会用TextView,这些都不是什么大问题。由于不同的项目的主题色调和字体颜色不同,所以我把这些可能改变的东西都放在了构造方法中,以便适应于不同的产品需求
/**
* Created by rongtao on 2016/11/19.
* 乐视****项目
* 倒计时
*/
public class CountDownUtils extends CountDownTimer {
private Button mView;//倒计时按钮
private Context mContext;
private int mNormal_bg,mNormal_txt_color;
/**
*
* @param context
* @param millisInFuture 倒计时总时长 单位毫秒
* @param countDownInterval 每次减少量(步长)单位毫秒
* @param btnView 倒计时按钮
* @param pressed_bg 按下时的按钮背景色
* @param normal_bg 正常的背景色
* @param pressed_txt_color 按下时的按钮文本颜色
* @param normal_txt_color 正常的按钮文本颜色
*/
public CountDownUtils(Context context, long millisInFuture, long countDownInterval, Button btnView, int pressed_bg, int normal_bg, int pressed_txt_color, int normal_txt_color) {
super(millisInFuture, countDownInterval);
this.mView = btnView;
this.mContext = context;
this.mNormal_bg=normal_bg;
this.mNormal_txt_color=normal_txt_color;
//在初始化的时候将按钮置灰,防止重复请求
mView.setBackgroundResource(pressed_bg);
setTextColor(pressed_txt_color);
mView.setClickable(false);//避免重复点击
}
/**
* 计时操作
* @param millisUntilFinished 计时时间的毫秒值
*/
@Override
public void onTick(long millisUntilFinished) {
Log.d("onTick", millisUntilFinished + "");
mView.setText(millisUntilFinished / 1000 + "秒后重新获取");
}
/**
* 计时结束
*/
@Override
public void onFinish() {
//计时结束后将按钮的状态复原
mView.setText("获取验证码");
mView.setClickable(true);
mView.setBackgroundResource(mNormal_bg);
setTextColor(mNormal_txt_color);
this.cancel();
}
private void setTextColor(int font_color) {
// ContextCompat.getColor(mContext,font_color); 可以用这个兼容方法,也可以自己手动判断
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
mView.setTextColor(mContext.getColor(font_color));
} else {
mView.setTextColor(mContext.getResources().getColor(font_color));
}
}
}
具体用法,一般都是在点击按钮后向服务器发送请求,当服务器返回的响应码为200的时候开启倒计时
//在请求成功后做此操作
new CountDownUtils(mContext,
5 * 1000,
1000,
mBtnGetCode,
R.drawable.bg_btn_reqcode_gray,
R.drawable.bg_btn_reqcode,
R.color.font_black,
R.color.font_common_theme)
.start();
下面附上CountDownTimer的系统源码,有兴趣的自己看,也就100多行,主要就是start,cancel以及handleMessage中的同步代码块
public abstract class CountDownTimer {
/**
* Millis since epoch when alarm should stop.
*/
private final long mMillisInFuture;
/**
* The interval in millis that the user receives callbacks
*/
private final long mCountdownInterval;
private long mStopTimeInFuture;
/**
* boolean representing if the timer was cancelled
*/
private boolean mCancelled = false;
/**
* @param millisInFuture The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
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;
}
/**
* Callback fired on regular interval.
* @param millisUntilFinished The amount of time until finished.
*/
public abstract void onTick(long millisUntilFinished);
/**
* Callback fired when the time is up.
*/
public abstract void onFinish();
private static final int MSG = 1;
// 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 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);
}
}
}
};
}