当前位置: 移动技术网 > IT编程>移动开发>Android > CountDownTimer 源码分析

CountDownTimer 源码分析

2018年02月23日  | 移动技术网IT编程  | 我要评论

《3feel》,肥牛牛贝斯,第五行动组

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

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

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网