zoukankan      html  css  js  c++  java
  • CountDownTimer 源码分析

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

     1 public class CountDownTimerActivity extends Activity {
     2 
     3     private Button mSend;
     4     private SendCountMessage mCountMessage;
     5 
     6     @Override
     7     protected void onCreate(Bundle savedInstanceState) {
     8         super.onCreate(savedInstanceState);
     9         this.setContentView(R.layout.activity_countdown);
    10 
    11         mCountMessage = new SendCountMessage();
    12         mSend = (Button) findViewById(R.id.sendCode);
    13         mSend.setOnClickListener(new View.OnClickListener() {
    14             @Override
    15             public void onClick(View v) {
    16                 mSend.setClickable(false);
    17                 //开始执行倒计时的功能
    18                 mCountMessage.start();
    19             }
    20         });
    21     }
    22 
    23 
    24     /**
    25      * 我们继承这个抽象类,然后设置好总共的倒计时的时间,以及间隔的时间
    26      * 并且重写 onTick和onFinish方法
    27      */
    28     class SendCountMessage extends CountDownTimer {
    29 
    30         /**
    31          * 这里我们还需要设置两个参数:
    32          * 第一个参数:表示我们倒计时的总时间
    33          * 第二个参数:表示我们倒计时的间隔,比如说我们是按一秒数还是二秒
    34          */
    35         public SendCountMessage() {
    36             super(60000, 1000);
    37         }
    38 
    39         /**
    40          * 该方法表示会在构造方法中设定的间隔时间下调用这个方法的。
    41          * 比如说我们设置了间隔时间为1秒的话,那么CountDownTimer
    42          * 将会每个一秒的时间调用 onTick方法一下
    43          * @param millisUntilFinished 表示距离倒计时结束的时间
    44          */
    45         public void onTick(long millisUntilFinished) {
    46             mSend.setText(millisUntilFinished/1000 + " 秒后重发");
    47         }
    48 
    49         /**
    50          * 这里表示倒计时完成结束了
    51          */
    52         public void onFinish() {
    53             mSend.setClickable(true);
    54         }
    55     }
    56 
    57     @Override
    58     protected void onDestroy() {
    59         super.onDestroy();
    60         /**
    61          * 最后在这里的时候,我们需要将CountDownTimer取消掉,因为如果我们在销毁界面的时候
    62          * 还没有取消该倒计时器的话,它还会一直在后台不断的跑的直到结束倒计最后才会结束的,
    63          * 这样子为了以免出现问题,我们这里需要取消掉,并且让系统gc该变量。
    64          */
    65         if(mCountMessage != null) {
    66             mCountMessage.cancel();
    67             mCountMessage = null;
    68         }
    69     }
    70 }

    界面布局:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical">
     6 
     7     ........
     8 
     9     <LinearLayout
    10         android:layout_width="fill_parent"
    11         android:layout_height="wrap_content"
    12         android:layout_marginBottom="20dip"
    13         android:layout_marginLeft="10dip"
    14         android:layout_marginRight="10dip"
    15         android:layout_marginTop="20dip">
    16 
    17         <EditText
    18             android:layout_width="0dip"
    19             android:layout_height="wrap_content"
    20             android:layout_weight="1"
    21             android:inputType="number"
    22             android:hint="请输入验证码" />
    23 
    24         <Button
    25             android:id="@+id/sendCode"
    26             android:layout_width="wrap_content"
    27             android:layout_height="wrap_content"
    28             android:text="发送验证码"
    29             android:textSize="18sp" />
    30 
    31     </LinearLayout>
    32 
    33 </LinearLayout>

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

    代码分析

     1 public CountDownTimer(long millisInFuture, long countDownInterval) {
     2     mMillisInFuture = millisInFuture;
     3     mCountdownInterval = countDownInterval;
     4 }
     5 
     6 public synchronized final CountDownTimer start() {
     7     mCancelled = false;
     8     if (mMillisInFuture <= 0) {
     9         onFinish();
    10         return this;
    11     }
    12     //通过当前开始的时间 + 倒计时的总时间来计算出结束的毫秒值
    13     mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
    14     //然后发送一个message消息给mHandler
    15     mHandler.sendMessage(mHandler.obtainMessage(MSG));
    16     return this;
    17 }

    mHandler里面的代码:

     1 // handles counting down
     2 private Handler mHandler = new Handler() {
     3 
     4     @Override
     5     public void handleMessage(Message msg) {
     6 
     7         synchronized (CountDownTimer.this) {
     8            //如果用户主动调用了取消方法,则返回
     9             if (mCancelled) {
    10                 return;
    11             }
    12 
    13             //第一步:首先判断结束的时间跟当前时间的差。
    14             final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
    15 
    16             //条件一: 如果小于等于0了,说明结束了。
    17             if (millisLeft <= 0) {
    18                 onFinish();
    19             } else if (millisLeft < mCountdownInterval) {
    20                 // no tick, just delay until done
    21                 //条件二: 如果距离结束的时间小于我们设定的间隔时间值的时候
    22                 //        这个时候就发送一个millisLeft延时的消息
    23                 sendMessageDelayed(obtainMessage(MSG), millisLeft);
    24             } else {
    25                 long lastTickStart = SystemClock.elapsedRealtime();
    26                 //调用我们的抽象方法,并且将距离结束的时间值当作参数回调出去
    27                 onTick(millisLeft);
    28 
    29                 // take into account user's onTick taking time to execute
    30                 long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
    31 
    32                 // special case: user's onTick took more than interval to
    33                 // complete, skip to next interval
    34                 while (delay < 0) delay += mCountdownInterval;
    35 
    36                 //发送一个延时的,时间间隔为我们设定的mCountdownInterval的消息出去
    37                 sendMessageDelayed(obtainMessage(MSG), delay);
    38             }
    39         }
    40     }
    41 };

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

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

    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }
  • 相关阅读:
    composer
    brew转为国内源
    轻松生成一个golang的docker应用程序
    轻松生成一个vue的静态nginx
    【OS_Windows】windows server设置多用户可同时远程连接
    【OS_Linux】centos中查看已有用户信息
    【OS_Linux】查看Linux系统版本的命令
    【OS_Linux】借助终端Xshell实现Centos文件的上传与下载
    【OS_Linux】终端XShell的安装与使用
    【OS_Linux】VMware 中安装CentOS7
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/8462340.html
Copyright © 2011-2022 走看看