倒计时的功能,比如说:发送短信验证码倒计时。

 public class CountDownTimerActivity extends Activity {

     private Button mSend;
private SendCountMessage mCountMessage; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_countdown); mCountMessage = new SendCountMessage();
mSend = (Button) findViewById(R.id.sendCode);
mSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSend.setClickable(false);
//开始执行倒计时的功能
mCountMessage.start();
}
});
} /**
* 我们继承这个抽象类,然后设置好总共的倒计时的时间,以及间隔的时间
* 并且重写 onTick和onFinish方法
*/
class SendCountMessage extends CountDownTimer { /**
* 这里我们还需要设置两个参数:
* 第一个参数:表示我们倒计时的总时间
* 第二个参数:表示我们倒计时的间隔,比如说我们是按一秒数还是二秒
*/
public SendCountMessage() {
super(, );
} /**
* 该方法表示会在构造方法中设定的间隔时间下调用这个方法的。
* 比如说我们设置了间隔时间为1秒的话,那么CountDownTimer
* 将会每个一秒的时间调用 onTick方法一下
* @param millisUntilFinished 表示距离倒计时结束的时间
*/
public void onTick(long millisUntilFinished) {
mSend.setText(millisUntilFinished/ + " 秒后重发");
} /**
* 这里表示倒计时完成结束了
*/
public void onFinish() {
mSend.setClickable(true);
}
} @Override
protected void onDestroy() {
super.onDestroy();
/**
* 最后在这里的时候,我们需要将CountDownTimer取消掉,因为如果我们在销毁界面的时候
* 还没有取消该倒计时器的话,它还会一直在后台不断的跑的直到结束倒计最后才会结束的,
* 这样子为了以免出现问题,我们这里需要取消掉,并且让系统gc该变量。
*/
if(mCountMessage != null) {
mCountMessage.cancel();
mCountMessage = null;
}
}
}

界面布局:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> ........ <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="20dip"> <EditText
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight=""
android:inputType="number"
android:hint="请输入验证码" /> <Button
android:id="@+id/sendCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送验证码"
android:textSize="18sp" /> </LinearLayout> </LinearLayout>

当我们不需要使用倒计时功能的时候,一定要要调用cancel()方法取消掉,不然它还会在我们页面销毁的时候继续执行的,很有可能会导致内存泄漏的问题

代码分析

 public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
} public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= ) {
onFinish();
return this;
}
//通过当前开始的时间 + 倒计时的总时间来计算出结束的毫秒值
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
//然后发送一个message消息给mHandler
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}

mHandler里面的代码:

 // 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(); //条件一: 如果小于等于0了,说明结束了。
if (millisLeft <= ) {
onFinish();
} else if (millisLeft < mCountdownInterval) {
// no tick, just delay until done
//条件二: 如果距离结束的时间小于我们设定的间隔时间值的时候
// 这个时候就发送一个millisLeft延时的消息
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 < ) delay += mCountdownInterval; //发送一个延时的,时间间隔为我们设定的mCountdownInterval的消息出去
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};

在创建构造函数之前会创建一个内部的Handler对象,主要是用于定时发送消息用的。当我们调用start()方法的时候会发送一个Handler消息出来,这个时候会在mHandler中进行处理。

当Handler收到消息之后就会去跟设定的时间间隔值进行一个比对,然后就发送一个延时的消息。

public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}

CountDownTimer 源码分析的更多相关文章

  1. Android 关于 CountDownTimer onTick() 倒计时不准确问题源码分析

    一.问题 CountDownTimer 使用比较简单,设置 5 秒的倒计时,间隔为 1 秒. final String TAG = "CountDownTimer"; * , ) ...

  2. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  3. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

随机推荐

  1. numpy中int类型与python中的int

    [code] import numpy as np nparr = np.array([[1 ,2, 3, 4]]) np_int32 = nparr[0][0] # np_int=1 py_int ...

  2. (转)关于python3中staticmethod(静态方法)classmethod(类方法)实例方法的联系和区别

    原文:http://dmcoders.com/2017/08/30/pythonclass/ https://zhuanlan.zhihu.com/p/28010894------正确理解Python ...

  3. C#:使用ListView动态添加数据一直闪烁的解决办法

    首先,自定义一个类ListViewNF,继承自 System.Windows.Forms.ListView using System; using System.Collections.Generic ...

  4. 本机spark 消费kafka失败(无法连接)

    本机spark 消费kafka失败(无法连接) 终端也不报错 就特么不消费:  但是用console的consumer  却可以 经过各种改版本 ,测试配置,最后发现 只要注释掉 kafka 配置se ...

  5. Quartz.NET基础知识概述

    Quartz.NET是什么 由于我现在使用的Quartz.NET2.2版本,相对2.x变化不大,主要是相对于1.x更新了很多东西,如下基础知识摘录网络. Quartz.NET是一个开源的作业调度框架, ...

  6. java多线程并发控制countDownLatch和cyclicBarrier的使用

    java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个处理都可以用一个线程来执行,所有处理完成了之后才会返回给用 ...

  7. Flutter踩坑日记:接入现有iOS项目

    之前搞的Flutter版工具链已经弄完了,感兴趣的朋友可以围观下,Android版本dio库(v2.0.14)发送网络请求老是报错,去官方提了issue还没回,于是今天搞一下把Flutter模块接入到 ...

  8. Linux cp 强制覆盖

     Linux下默认cp命令是有别名(alias cp='cp -i')的,无法强制覆盖,即使你用 -f 参数也无法强制覆盖文件,下面提供两种Linux下cp 覆盖方法. 1) 取消cp的alias,这 ...

  9. Python3 中使用sys.argv详解

    #/usr/bin/env python #coding:utf-8 import sys # print(sys.argv[1]) def readFile(filename): "&qu ...

  10. Spring IOC 源码之ResourceLoader

    转载自http://www.blogjava.net/DLevin/archive/2012/12/01/392337.html 在<深入Spring IOC源码之Resource>中已经 ...