Android 倒計時工具CountDownTimer的使用

1、用法詳解

在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

相關文章
相關標籤/搜索