Android 倒计时工具CountDownTimer的使用

一、用法详解

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

 

二、核心源码解析

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线程的负担?


此外、主线程队列阻塞、倒计时的准确度如何?

try doing it!

转载于:https://my.oschina.net/ososchina/blog/347859

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值