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<TextView> 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;
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/192285.html原文链接:https://javaforall.cn
相关文章
- 使用pycharm中全文搜索快捷键(整个项目搜索)[通俗易懂]
- Android使用系统签名以及安装[通俗易懂]
- [新人向]MySQL和Navicat下载、安装及使用详细教程[通俗易懂]
- Quartz入门以及相关表达式使用[通俗易懂]
- 关于windos 10 恶意软件删除工具的使用[通俗易懂]
- Oracle number数据类型的使用[通俗易懂]
- 使用google earth engine(GEE)提取2000年到2019年长江下游水体(河流、湖泊)数据[通俗易懂]
- 优先级队列的使用[通俗易懂]
- linux进程管理命令使用_shell进程
- OllyDbg使用教程[通俗易懂]
- Python使用captcha制作验证码[通俗易懂]
- 使用VIM搜索多个文件[通俗易懂]
- 使用Sigar包获取操作系统信息[通俗易懂]
- 【Laravel系列4.4】模型Eloquent ORM的使用(二)
- 使用docker运行redmine
- 万万没想到,go也能使用对象来操作数据库了,网友直呼:健壮性有保证了
- 【Windows 逆向】OD 调试器工具 ( CE 工具通过查找访问的方式找到子弹数据基地址 | 使用 OD 工具附加游戏进程 | 在 OD 工具中查看子弹数据地址 | 推荐 )
- 使用hexo创建自己的博客
- Oracle 视图 DBA_WORKLOAD_SCHEDULE_CAPTURES 官方解释,作用,如何使用详细说明
- 如何使用 Ansible 打补丁以及安装应用
- Dropbox是一个提供同步本地文件的网络存储在线应用,支持在多台电脑多种操作中自动同步,并可当作大容量的网络硬盘使用。
- 如何使用Linux查看磁盘分区情况?(linux查看分区)
- MySQL为你带来更多便利使用C封装了MySQL(c mysql包)
- 使用排序数组存储至Redis服务器管理(排序数组存储到redis)
- Oracle中使用非等值链接技巧的探索(oracle中非等值链接)
- 探讨phpdefine()函数及defined()函数使用详解
- jsp中定义和使用方法示例介绍
- java使用listIterator逆序arraylist示例分享