在Android开发中,有时须要使用倒计时功能,在Android系统中提供了一个倒计时的抽象类来辅助倒计时行为。android
public class CountDownTimeActivity extends Activity implements OnClickListener { TextView mTextView; Button mButton1; Button mButton2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.countdown); mTextView = (TextView)findViewById(R.id.textView1); mButton1 = (Button)findViewById(R.id.button1); mButton2 = (Button)findViewById(R.id.button2); mButton1.setOnClickListener(this); mButton2.setOnClickListener(this); } CountDownTimer timer = new CountDownTimer(40000,1000) { //定义40秒,每一秒执行一次 @Override public void onTick(long millisUntilFinished) { mTextView.setText("seconds remaining: " + millisUntilFinished / 1000); //millisUntilFinished不是精确值,须要进行计算millisUntilFinished / 1000 } @Override public void onFinish() { mTextView.setText("done!"); } }; @Override public void onClick(View v) { switch(v.getId()){ case R.id.button1: timer.start(); break; case R.id.button2: timer.cancel(); //取消后中止运行。下次还会从新开始,而不是接着开始 break; } } }
这个类有点缺陷,就是不能暂停后再次接着继续使用,为此,须要自定义一个相似的倒计时计时器并发
package android.os; import android.util.Log; public abstract class CountDownTimer { private final long mMillisInFuture; private final long mCountdownInterval; private long mStopTimeInFuture; private long millisUntilFinished = 0; private boolean isPause = false; public CountDownTimer(long millisInFuture, long countDownInterval) { mMillisInFuture = millisInFuture; mCountdownInterval = countDownInterval; } public final void cancel() { mHandler.removeMessages(MSG); } public final void pause() { cancel(); isPause = true; } public synchronized final CountDownTimer start() { if (mMillisInFuture <= 0) { onFinish(); return this; } mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture; if(isPause) { mStopTimeInFuture = mStopTimeInFuture - millisUntilFinished; isPause = false; } mHandler.sendMessage(mHandler.obtainMessage(MSG)); return this; } public abstract void onTick(long millisUntilFinished); public abstract void onFinish(); private static final int MSG = 1; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { synchronized (CountDownTimer.this) { final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime(); if (millisLeft <= 0) { onFinish(); millisUntilFinished = 0; } else if (millisLeft < mCountdownInterval) { sendMessageDelayed(obtainMessage(MSG), millisLeft); } else { long lastTickStart = SystemClock.elapsedRealtime(); onTick(millisLeft); millisUntilFinished = millisLeft; long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime(); while (delay < 0) delay += mCountdownInterval; sendMessageDelayed(obtainMessage(MSG), delay); } } } }; }
2、核心源码解析async
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) { // 剩余时间小于一次时间间隔的时候,再也不通知,只是延迟一下 sendMessageDelayed(obtainMessage(MSG), millisLeft); } else { long lastTickStart = SystemClock.elapsedRealtime(); onTick(millisLeft); // 处理用户onTick执行的时间 long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime(); // 特殊状况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次interval while (delay < 0) delay += mCountdownInterval; sendMessageDelayed(obtainMessage(MSG), delay); } } } };
经过源码可知,CountDownTimer采用的是handler机制,经过sendMessageDelayed延迟发送一条message到主线程的looper中,而后在自身中收到以后判断剩余时间,并发出相关回调,而后再次发出message的方式。以前实现这种倒计时是经过asynctask,在线程中经过Thread.sleep来实现,经过asyntask的cancel来实现取消,经过构造asynctask传入接口的实现来onTick的相似功能。这个CountDownTimer默认是在当前looper当中,能够是在UI线程也能够是在非UI线程中执行,若是在UI线程中执行,那是否是会稍微加剧UI线程的负担?ide
此外、主线程队列阻塞、倒计时的准确度如何?oop
try doing it!this