CountDownTimer浅析
一,概述
在项目开发中经常会用到倒计时这个功能,而Android也帮我们封装好了一个类CountDownTimer,给我们的开发带来了很大的方便;
二,API
CountDownTimer (long millisInFuture, long countDownInterval)
参数1,设置倒计时的总时间(毫秒)
参数2,设置每次减去多少毫秒
- 1
- 2
- 3
三,基本用法
以App中获短信取验证码为例:
private Button btn;private TextView vertifyView; @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initView();}private void initView(){vertifyView =(TextView) findViewById(R.id.vertifyView);btn =(Button) findViewById(R.id.button);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//1,请求后台...//2,触发定时器刷新UI(启动代码最好放在请求后台回调成功之后)timer.start();}});}private CountDownTimer timer = new CountDownTimer(10000, 1000) { @Override public void onTick(long millisUntilFinished) { vertifyView.setText((millisUntilFinished / 1000) + "秒后可重发"); } @Override public void onFinish() { vertifyView.setEnabled(true); vertifyView.setText("获取验证码"); } };
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
ok~这样一个基本的CountDownTimer案例就完成了
四,存在的问题
CountDownTimer如果使用不当,常常会报空指针异常,甚至造成严重的内存泄漏
5.0源码:
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 downprivate Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {synchronized (CountDownTimer.this) {if (mCancelled) {return;}final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();if (millisLeft <= 0) {onFinish();} else if (millisLeft < mCountdownInterval) {// 剩余时间小于一次时间间隔的时候,不再通知,只是延迟一下sendMessageDelayed(obtainMessage(MSG), millisLeft);} else {long lastTickStart = SystemClock.elapsedRealtime();onTick(millisLeft);// 处理用户onTick执行的时间long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();// 特殊情况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次intervalwhile (delay < 0) delay += mCountdownInterval;sendMessageDelayed(obtainMessage(MSG), delay);}}}};
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
从源码中我们可以看出,CountDownTimer的内部实现是采用Handler机制,通过sendMessageDelayed延迟发送一条message到主线程的looper中,然后在自身中收到之后判断剩余时间,并发出相关回调,然后再次发出message的方式。
这样的方式其实是有一定弊端的,那就是如果在Activity或者Fragment被回收时并未调用CountDownTimer的cancel()方法结束自己,这个时候CountDownTimer的Handler方法中如果判断到当前的时间未走完,那么会继续调用
sendMessageDelayed(obtainMessage(MSG), delay);
- 1
触发
onTick(millisLeft);
- 1
当回调了Activity或者fragment中CountDownTimer的onTick方法时,Activity或者Fragment已经被系统回收,从而里面的变量被设置为Null,再调用
vertifyView.setText((millisUntilFinished / 1000) + "秒后可重发");
- 1
vertifyView为空,也就空指针了~
同时,CountDownTimer中的Handler方法还在继续执行,这一块空间始终无法被系统回收也就造成了内存泄漏问题。
五,总结
1,在CountDownTimer的onTick方法中记得判空
activity中if(!activity.isFinishing()){//doing something...}fragment中if(getActivity()!=null){//doing something...}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2,在配合DialogFragment使用时,如果在onFinish()方法调用了 dismiss()方法让弹框消失,记得 判断getFragmentManager是否为空
@Overridepublic void onFinish() {if(getFragmentManager()!=null){dismiss();}}
- 1
- 2
- 3
- 4
- 5
- 6
3,在使用CountDownTimer时,在宿主Activity或fragment生命周期结束的时候,记得调用timer.cancle()方法
@Overridepublic void onDestroy() {if(timer!=null){timer.cancel();timer = null;}super.onDestroy();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
遇到问题还是尽量先从控件的源码中寻找答案~相信源码是最好的老师O(∩_∩)O哈哈~
CountDownTimer浅析相关推荐
- CountDownTimer 实现验证码倒计时
先看下完整的代码,如是使用入职过去即可 public class MainActivity extends AppCompatActivity {private TextView code;@Over ...
- CountDownTimer的简单使用
下面是60秒的倒计时 activity public class MainActivity extends AppCompatActivity {private TextView time; @Ove ...
- 浅析 JavaScript 中的 函数 uncurrying 反柯里化
柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...
- 浅析Python中bytes和str区别
本博转载自:Chown-Jane-Y的浅析Python3中的bytes和str类型 Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示, ...
- 学习《Linux设备模型浅析之设备篇》笔记(深挖一)
这篇文章既然说了是浅析,那就是跳过了一些东西,我们把这些跳过的东西给它尽可能的补回来 今天登陆 lxr.free-electrons.com 发现内核版本已经升级到3.15了,那以后都使用3.15的源 ...
- 学习《Linux设备模型浅析之设备篇》笔记(一)
最近在学习Linux设备模型,前面几篇文章也是读这篇的时候遇到问题,然后为了搞清楚先转去摸索才写出来的. 当然了,刚开始是先读到<Linux那些事儿之我是Sysfs>,搞不清楚才去读的&l ...
- 架构周报| 浅析MySQL JDBC连接配置上的两个误区
经典案例 \\ 浅析MySQL JDBC连接配置上的两个误区:相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很 ...
- 超级账本(Hyperledger Fabric)之权限管理浅析
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 超级账本(Hyperledger Fabric)之权限管理浅析 超级账本是联盟链的代表,而其相对于共链(例如比特币,以太 ...
- linux内核SMP负载均衡浅析
需求 在<linux进程调度浅析>一文中提到,在SMP(对称多处理器)环境下,每个CPU对应一个run_queue(可执行队列).如果一个进程处于TASK_RUNNING状态( ...
最新文章
- ubuntu 在线安装mysql_Ubuntu下安装MySQL5.6
- 基于SSM实现个人健康管理系统
- Java控制语句——switch语句
- Hadoop JobHistory
- 【C/C++】C/C++博客汇总
- 51nod---无法表示的数
- EXCEL数据汇总-数据透视图
- 我的第一个wp8小程序
- 重启nginx后丢失nginx.pid的解决方法(转)
- BZOJ3261: 最大异或和(可持久化trie树)
- Tip:在使用AjaxControlTookit的控件时响应事件
- 往PPT幻灯中添加图片的方法有哪些?
- matlab开关电源仿真软件,开关电源仿真设计软件选择
- ios15验证失败因为你不在连接互联网
- 【关于四足机器人那些事】足端轨迹规划-复合摆线轨迹
- 致所有仍然关注BreezeMaphack的朋友
- 基于FPGA的电子计算器设计(下)
- phpstudy一直自动停止启动_window10 phpstudy2018 mysql服务重启之后自动停止
- bzoj3659 Which Dreamed It BEST定理(公式绝对没错doge)
- ​力扣解法汇总2315. 统计星号