Android中CountDownTimer类详解

  一、概述

  项目中经常用到倒计时的功能,比如说限时抢购,手机获取验证码等等。而google官方也帮我们封装好了一个类:CountDownTimer,使我们的开发更加方便;

  二、API

  CountDownTimer是一个抽象类,有两个抽象方法,它的API很简单

  public abstract void onTick(long millisUntilFinished);//这个是每次间隔指定时间的回调,millisUntilFinished:剩余的时间,单位毫秒

  public abstract void onFinish();//这个是倒计时结束的回调

  使用的时候只需要

  new CountDownTimer(long millisInFuture, long countDownInterval)

  //millisInFuture:倒计时的总时长

  //countDownInterval:每次的间隔时间 单位都是毫秒

  三、基本使用方法

  我们以短信验证码的倒计时来看,点击获取验证码,倒计时60s不可点击

  new CountDownTimer(60 * 1000, 1000) {

  @Override

  public void onFinish() {

  if (tvCode != null) {

  tvCode.setText("重新获取");

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

  点击按钮,获取验证码成功之后就可以执行以上操作,最后一定要start,不然不会执行

  四、使用注意

  CountDownTimer使用很简单,但是坑很多,需要注意避免踩坑。

  1、空指针:

  如果在activity或者fragment关闭销毁的时候没有调用cancle方法,它的onTick方法还是会继续执行,这个时候UI控件都为空,不注意判断的话很容易空指针

  2、时间不是太准的问题:

  我们看CountDownTimer的源码可以看到,在执行onTick的方法时,google源码里面减去了程序执行到这里的时候所消耗的时间,这里可以看出google代码的严谨

  final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

  if (millisLeft <= 0) {

  onFinish();

  } else if (millisLeft < mCountdownInterval) {

  // no tick, just delay until done

  sendMessageDelayed(obtainMessage(MSG), millisLeft);

  }

  所以一开始倒计时的时间是59,这里可以在构造方法里面稍微加一点时间就可以解决如:

  new CountDownTimer(60 * 1000+300, 1000)

  3、内存泄漏问题

  首先我们来看源码,核心代码如下

  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,所以很容易造成内存泄漏问题,当Activity或者Fragment关闭而倒计时还未结束的时候,会在后台一直执行,而很多时候我们用倒计时会有更新UI的操作,而控件都持有activity的引用,长期得不到释放的话就会造成内存泄漏,甚至会造成1所说的空指针问题,所以一般要在activity或fragment销毁的时候调用cancle方法。

  我自己把这个进行了封装,写成了一个工具类以供参考:

  public class TimeUtils {

  private String color;//这里可以修改文字颜色

  WeakReference tvCodeWr;//控件软引用,防止内存泄漏

  private CountDownTimer timer;

  public TimeUtils(TextView tvCode, String color) {

  super();

  this.tvCodeWr = new WeakReference(tvCode);

  this.color = color;

  }

  //这是倒计时执行方法

  public void RunTimer() {

  timer = new CountDownTimer(60 * 1000 - 1, 1000) {

  @Override

  public void onFinish() {

  if (tvCodeWr.get() != null) {

  tvCodeWr.get().setText("重新获取");

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

  }

  //这个方法可以在activity或者fragment销毁的时候调用,防止内存泄漏

  public void cancle() {

  if (timer != null) {

  timer.cancel();

  timer = null;

  }

  }

  }

  到此这篇关于Android中CountDownTimer类详解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  您可能感兴趣的文章: