当前位置:   article > 正文

CountDownTimer的使用和原理_countdowntimer 怎么延时开始

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

再来看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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

对应布局如下

<?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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

可以看到,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);
                }
            }
        }
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

总结

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

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/808917
推荐阅读
相关标签
  

闽ICP备14008679号