您的位置:首页 > 其它

安卓中短信验证码倒计时的几种方式

2017-12-21 15:17 393 查看
发送短信验证码后,一般在界面上都会有一个倒计时的显示.在安卓中,实现类似的倒计时有多种方式,当然背后的基本原理都是设定一个初始值,然后每过一定的间隔时间执行操作.

用安卓自带的CountDownTimer实现

这是最简洁的实现方式.安卓提供了一个CountDownTimer类用于倒计时功能.其使用方法在注释里面写的已经比较清楚了.记时开启后禁掉控件的点击事件,倒计时结束后再开启.防止重复点击导致多个任务运行.

private void countDownTime() {
//用安卓自带的CountDownTimer实现
CountDownTimer mTimer = new CountDownTimer(60 * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
Log.i(TAG, "millisUntilFinished: " + millisUntilFinished);
btn1.setText(millisUntilFinished / 1000 + "秒后重发");
}

@Override
public void onFinish() {
btn1.setEnabled(true);
btn1.setText("发送验证码");
cancel();
}
};
mTimer.start();
btn1.setEnabled(false);
}


CountDownTimer内部也是用Handler实现的.形参是总记时时间和时间间隔.当倒计时任务开始后,在handleMessage方法中会不断调用sendMessageDelayed方法,相当于每隔一段时间后回调onTick方法,这里就可以做界面实时更新的逻辑.内部有一个millisLeft记录剩余的时间,<=0时会回调onFinish方法.此时最好调用一次cancel方法,内部的Handler会移除之前定义的消息.

11-21 11:51:18.529 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 59999
11-21 11:51:19.530 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 58998
11-21 11:51:20.532 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 57996
11-21 11:51:21.534 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 56993
11-21 11:51:22.538 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 55990
11-21 11:51:23.540 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 54988
11-21 11:51:24.542 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 53986
11-21 11:51:25.544 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 52984
11-21 11:51:26.545 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 51982
11-21 11:51:27.548 12704-12704/com.mercury.countdown I/Main2Activity: millisUntilFinished: 50980


但是发送通知的间隔时间并非直接等于传入的参数,而是会通过SystemClock.elapsedRealtime()方法计算得出.这个值得到的是手机本次开机后到当前的总时间.每次累计的时候会有几毫秒的误差,最终导致显示的时候某个时间值可能不是很准确.上面的日志显示了倒计时开始后的实时时间,预先定义的间隔为1000毫秒.

用Java的TimerTask配合Timer实现(定时任务)

private void usingTimer() {
//使用Java的Timer配合TimerTask(定时任务)
time = 60;
final Timer timer = new Timer();
mTimerTask=new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (time <= 0) {
cancel();
btn2.setEnabled(true);
btn2.setText("发送验证码");
} else {
btn2.setEnabled(false);
btn2.setText(time + "秒后重发");
}
Log.i(TAG, "time: " + time);
time--;
}
});
}
};

timer.schedule(mTimerTask, 0, 1000);
}


该方法的原理是开启了一个线程,并执行定时操作.因为TimerTask是Java中一个实现了Runnable接口的抽象类,配合Timer类可以完成一段时间或者重复性的任务.Timer类中的schedule方法将二者联系在一起,简单的说Timer负责记时,TimerTask负责执行具体的任务.这里我们定义了一个倒计时的初始值time=60(s),run方法每隔给定的时间间隔后执行一次.当倒计时结束后一定要手动调用cancel,否则后台任务会一直执行下去,造成资源的浪费.更新控件的操作要放在UI线程中操作.

这种方法的好处是时间值相对准确,并且应用场景不止于验证码倒计时.将定义的time类型修改为static,还可以实现倒计时在页面销毁后正常计时,再次创建页面后仍显示准确的值.

用Handler的方式实现

private static class MyHandler extends Handler {

WeakReference<Main2Activity> mReference;

private MyHandler(Main2Activity activity) {
mReference = new WeakReference<>(activity);
}

@Override
public void handleMessage(Message msg) {
Main2Activity main2Activity = mReference.get();
if (main2Activity.time > 0) {
main2Activity.btn3.setText(main2Activity.time + "秒后重发");
main2Activity.btn3.setEnabled(false);
} else {
main2Activity.btn3.setText("发送验证码");
main2Activity.btn3.setEnabled(true);
}
}
}


//触发倒计时的点击事件
private void useHandler() {
final MyHandler handler = new MyHandler(this);
time = 60;
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
while (time >= 0) {
time--;
handler.sendEmptyMessage(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
}


基本原理就是利用Handler在主线程和子线程之间进行通信.此处的时间间隔用的是线程休眠1000毫秒,基本和延迟发送消息一个意思.需要注意的是内部类会持有外部类的引用,因此Activity销毁后Handler中有耗时操作还持有其引用,就会造成内存泄露.因此需要将Handler声明为静态内部类,并且持有Activity的弱引用,这样可以操作类中声明的控件和变量,而不必将它们全部声明为静态的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: