CountDownTimer的使用和原理

转载请标明出处:
http://blog.csdn.net/mr_lawen/article/details/53381484

在我们的安卓项目中有时会有倒计时的需求,官方为我们提供了CountDownTimer这个类。下面就说说它的使用和原理。

使用方式

CountDownTimer是一个抽象类,我们需要定义一个它的实现类MyCountDownTimer(也可以直接在MainActivity中采用匿名类的方式)。

public class MyCountDownTimer extends CountDownTimer{

    private onCountDownListener listener;
    //第一个参数为倒计时总时长,第二个参数为倒计间隔
    public MyCountDownTimer(long millisInFuture, long countDownInterval, onCountDownListener listener) {
        super(millisInFuture, countDownInterval);
        this.listener = listener;
    }

    @Override
    public void onTick(long millisUntilFinished) {
        //参数单位为毫秒,转化为秒
        long time = millisUntilFinished / 1000;
        //回调onTickShow()方法,传入倒计时剩余时间
        listener.onTickShow(time);
    }

    @Override
    public void onFinish() {
        //倒计时完成,回调onFinishShow()方法
        listener.onFinishShow();
    }

    public interface onCountDownListener {
        void onTickShow(long left_time);
        void onFinishShow();
    }
}

再来看MainActivity

public class MainActivity extends AppCompatActivity {

    private TextView tv_time_left;
    private TextView tv_1;
    private TextView tv_2;
    private MyCountDownTimer mMyCountDownTimer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_time_left = (TextView) findViewById(R.id.tv_time_left);
        tv_1 = (TextView) findViewById(R.id.tv_1);
        tv_2 = (TextView) findViewById(R.id.tv_2);
        //实例化一个MyCountDownTimer对象,传入倒计总时长为10s,间隔为1s
        //实例化一个onCountDownListener对象传入,重写两个方法,更新UI。
        mMyCountDownTimer = new MyCountDownTimer(10000, 1000, new MyCountDownTimer.onCountDownListener({
            @Override
            public void onTickShow(long left_time) {
                tv_time_left.setText(left_time+"");
            }

            @Override
            public void onFinishShow() {
                tv_time_left.setText("砰,炸弹爆炸了!");
                tv_1.setText("");
                tv_2.setText("");
            }
        });
        //start方法开启倒计时
        mMyCountDownTimer.start();
    }
}

对应布局如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context="com.example.qn.countdowntimerdemo.MainActivity">

    <TextView
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="总倒计时长10s,倒计间隔为1s" />
    <LinearLayout
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="炸弹将在"/>
        <TextView
            android:id="@+id/tv_time_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#FF0000"
            android:text="60"/>
        <TextView
            android:id="@+id/tv_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="s后爆炸,请迅速撤离!"/>
    </LinearLayout>

</LinearLayout>

可以看到,CountDownTimer使用起来并不难,主要是重写它的两个方法onTick()和onFinish()。用起来不难的话,我们就应该看看它的原理。

原理解释
看源码

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;
    }
   //取消倒计时
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    //start方法开始倒计时
    public synchronized final CountDownTimer start() {
        mCancelled = false;
        if (mMillisInFuture <= 0) {
            onFinish();
            return this;
        }
       //倒计时停止时间 = 当前机器时间 + 倒计时总时长
        mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
        //发送一个消息开始倒计时
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }

    //该方法就是我们在MyCountDownTimer里重写的方法,每一个倒计时间隔调用一次,下面的代码//中就可以看到
    public abstract void onTick(long millisUntilFinished);

    //倒计时结束,也是我们需要重写的方法
    public abstract void onFinish();

    private static final int MSG = 1;

    //可以看到这里用Handler进行发送消息和处理消息
    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {

            synchronized (CountDownTimer.this) {
                if (mCancelled) {
                    return;
                }
                //剩余时间 = 倒计时结束时间 – 当前机器时间
                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
                //如果剩余时间<=0,结束倒计时
                if (millisLeft <= 0) {
                    onFinish();
                } else if (millisLeft < mCountdownInterval) { 
                    //剩余时间不足一个倒计时间隔,那么就发送一个延时大小为剩余时间的消息
                    sendMessageDelayed(obtainMessage(MSG), millisLeft);
                } else {
                    //否则
                    //记录下调用onTick()方法前的机器时间
                    long lastTickStart = SystemClock.elapsedRealtime();
                    //这里就是上面说的每个一个倒计时间隔就调用一个onTick()方法,传入剩余时//间
                    onTick(millisLeft);

                    //由于onTick()方法的执行耗费了一定的时间,所以延时消息的延时时间现在不//能是一个倒计时间隔了。
                    //它等于倒计时间隔 – onTick()方法执行时间
                    //即delay = mCountdownInterval – (当前机器时间 - 方法执行前的机器时间)
                    //即delay = mCountdownInterval-( SystemClock.elapsedRealtime()-lastTickStart)
                    //也就等于下面的式子。
                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

                    //这里是一个特殊情况,防止delay是一个负值,即onTick花费时间超过了
                    //一个倒计时间隔
                    while (delay < 0) delay += mCountdownInterval;
                    //发出延时时间为delay的消息。
                    sendMessageDelayed(obtainMessage(MSG), delay);
                }
            }
        }
    };
}

总结

CountDownTimer利用传进来的倒计时间隔,发送延时消息,在消息处理时,每次间隔都调用一次onTick(),而我们早onTick()里做一些更新UI的操作,这就形成了倒计时的现象。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值