这里介绍一下短信验证码读秒的程序,下面我找了一张图片。
首先来介绍一下CountDownTimer实现的获取验证码的倒计时。这里给出详细的编码。
xml文件配置:
- shape_button_type1.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FF4583C9"/>
<corners android:radius="5dp"/>
<stroke android:color="#FF4583C9" android:width="1dp"/>
</shape>
- shape_button_type2.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFDDDDDD"/>
<corners android:radius="5dp"/>
<stroke android:color="#FFDDDDDD" android:width="1dp"/>
</shape>
- selector_button.xml
布局文件:<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/shape_button_type1" android:state_enabled="true"/> <item android:drawable="@drawable/shape_button_type2" android:state_enabled="false"/> </selector>
接下来就是代码,代码的内容主要是按钮的点击事件,事件发送验证码,最后退出程序时,取消。<?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"> <Button android:id="@+id/send_verifcode" android:layout_width="match_parent" android:layout_height="60dp" android:layout_marginTop="24dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:background="@drawable/selector_button" android:text="点击发送验证码" android:textColor="#ffffff" android:textSize="24dp"/> </LinearLayout>
public class MainActivity2 extends AppCompatActivity{ private Button sendVerifCodeBT; private CountDownTimer mCountDownTimer; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); sendVerifCodeBT = (Button) findViewById(R.id.send_verifcode); sendVerifCodeBT.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendVerifCode(); Toast.makeText(MainActivity2.this, "发送验证码", Toast.LENGTH_SHORT).show(); } }); } private void sendVerifCode(){ //第一个参数为总时长,第二个参数为间隔多长时间执行 mCountDownTimer = new CountDownTimer(10000, 1000) { @Override public void onTick(long millisUntilFinished) { //计时中 sendVerifCodeBT.setEnabled(false); sendVerifCodeBT.setText(millisUntilFinished / 1000 + "秒后可重新发送"); } @Override public void onFinish() { //计时结束 sendVerifCodeBT.setEnabled(true); sendVerifCodeBT.setText("重新获取验证码"); } }; mCountDownTimer.start(); //开启计时器 } @Override protected void onDestroy() { super.onDestroy(); if (mCountDownTimer != null){ mCountDownTimer.cancel(); //取消计时器 } } }
这里主要调用了new CountDownTimer(60000,1000);并实现了其中的两个方法,一个方法是onTik();方法,该方法是在计时器内执行,另一个方法是,计时器的时间运行完了,调用该方法。在想调用的时候,调用start()方法开启启动,并在取消的时候调用cancel()方法。
那么在说另一个方法,这个利用Timer计时器来完成,请看:
其中调用runOnUiThread()方法是将在主线程中更新ui。同时还可以这样,在想要更新的地方发送Handler,在handler中处理更新UI。private Timer mTimer = new Timer(); private int time;
private void sendVerifCode2(){ time = 60; TimerTask timerTask = new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { if (time < 0) { sendVerifCodeBT.setEnabled(true); sendVerifCodeBT.setText("重新获取验证码"); } else { sendVerifCodeBT.setEnabled(false); sendVerifCodeBT.setText(time + "秒后重新获取"); } time--; } }); } }; mTimer.schedule(timerTask,0,1000); }
<pre style="font-family: 宋体; font-size: 9.6pt; background-color: rgb(255, 255, 255);"><pre name="code" class="html">@Override protected void onDestroy() { super.onDestroy(); if (mTimer != null){ //取消计时器 mTimer.cancel(); } }
接下再来阅读以下CountDownTimer的源码。这个源码很简单:
public abstract class CountDownTimer { /** * 设置总时间 */ private final long mMillisInFuture; /** * 每隔多少秒调用回调函数 */ private final long mCountdownInterval; private long mStopTimeInFuture; /** * 是否取消回调函数 */ private boolean mCancelled = false; /** * 构造函数,设置总时间和相隔时间 以毫秒为单位 */ public CountDownTimer(long millisInFuture, long countDownInterval) { mMillisInFuture = millisInFuture; mCountdownInterval = countDownInterval; } /** * 取消,handler发送取消信息 */ public synchronized final void cancel() { mCancelled = true; mHandler.removeMessages(MSG); } /** * 开始。首先设置取消为false,并判断总时间是否<=0,是结束计时。否则先获取停止的时间点,并发送消息 */ public synchronized final CountDownTimer start() { mCancelled = false; if (mMillisInFuture <= 0) { onFinish(); return this; } mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture; mHandler.sendMessage(mHandler.obtainMessage(MSG)); return this; } /** * 计时时事件回调,直到结束 */ public abstract void onTick(long millisUntilFinished); /** * 计时结束回调 */ public abstract void onFinish(); private static final int MSG = 1; // 内部处理handler,判断最后结束时间与当前时间之差是否>=0,如果小于,调用结束方法,小于相隔时间,不调用onTik()方法,延迟发送信息
// 大于则处理onTik()方法,获取延迟发送的秒数,并发送信息。
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,还一个是Timer,有一个不能忽视的地方是,在不用的时候需要取消,在onDestroy()方法中取消,一定要这样做,因为开启计时功能后,立刻退出程序,按照逻辑,计时器是需要停掉的,但是在切换回来的时候,还在计数。所以一定不要在一些方法中调用cancel()方法。