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

相关文章
相关标签/搜索