Android将倒计时做到极致

前言

倒计时的实现有很多方式,我觉得分享这个技术的关键在于有些官方的,甚至第三方的,也许能帮我实现99%的效果,但是当你从99%优化到100%,哪怕这1%微不足道,但你能从这个过程中得到的东西远远比你想象中的要多。

已有倒计时方案存在的问题

在开发倒计时功能时往往我们会为了方便直接使用CountDownTimer或者使用Handler做延时来实现,当然CountDownTimer内部封装也是使用的Handler。

如果只是做次数很少的倒计时或者不需要精确的倒计时逻辑那倒没关系,比如说我只要倒计时10秒,或者我大概5分钟请求某个接口

但是如果是需要做精确的倒计时操作,比如说手机发送验证码60秒,那使用现有的倒计时方案就会存在问题。可能有些朋友没有注意到这一点,下面我们就来简单分析一下现有倒计时的问题。

1. CountDownTimer

这个可能是用得最多的,因为方便嘛。但其实倒计时每一轮倒计时完之后都是存在误差的,如果看过CountDownTimer的源码你就会知道,他的内部是有做校准操作的。(源码很简单这里就不分析了)

但是如果你认真的测试过CountDownTimer,你就会发现,即便它内部有做校准操作,他的每一轮都是有偏差,只是他最后一次倒计时完之后的总共时间和开始倒计时的时间相比没偏差。
什么意思呢,意思就是1秒,2.050秒,3.1秒…,这样的每轮偏差,导致他会出现10.95秒,下一次12秒的情况,那它的回调中如果你直接做取整就会出现少一秒的情况,但实际是没少的。
这只是其中的一个问题,你可以不根据它的回调做展示,自己用一个整形累加做展示也能解决。但是他还有个问题,有概率直接出现跳秒,就是比如3秒,下次直接5秒,这是实际的跳秒,是少了一次回调的那种。

跳秒导致你如果直接使用它可能会大问题,你可能自测的时候没发现,到时一上线应用在用户那概率跳秒,那就蛋疼了。

2. Handler

不搞这么多花里胡哨的,直接使用Handler来实现,会有什么问题。
因为直接使用handler来实现,没有校准操作,每次循环会出现几毫秒的误差,虽然比CountDownTimer的十几毫秒的误差要好,但是在基数大的倒计时情况下误差会累计,导致最终结果和现实时间差几秒误差,时间越久,误差越大

3. Timer

直接使用Timer也一样,只不过他每轮的误差更小,几轮才有1毫秒的误差,但是没有校准还是会出现误差累计,时间越久误差越大。

自己封装倒计时

既然无法直接使用原生的,那我们就自己做一个。
我们基于Handler进行封装,从上面可以看出主要为了解决两个问题,时间校准和跳秒。自己写一个CountDownTimer

public class CountDownTimer {

    private int mTimes;
    private int allTimes;
    private final long mCountDownInterval;
    private final Handler mHandler;
    private OnTimerCallBack mCallBack;
    private boolean isStart;
    private long startTime;

    public CountDownTimer(int times, long countDownInterval){
        this.mTimes = times;
        this.mCountDownInterval = countDownInterval;
        mHandler = new Handler();
    }

    public synchronized void start(OnTimerCallBack callBack){
        this.mCallBack = callBack;
        if (isStart || mCountDownInterval <= 0){
            return;
        }

        isStart = true;
        if (callBack != null){
            callBack.onStart();
        }
        startTime = SystemClock.elapsedRealtime();

        if (mTimes <= 0){
            finishCountDown();
            return;
        }
        allTimes = mTimes;

        mHandler.postDelayed(runnable, mCountDownInterval);
    }

    private final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            mTimes--;
            if (mTimes > 0){
                if (mCallBack != null){
                    mCallBack.onTick(mTimes);
                }

                long nowTime = SystemClock.elapsedRealtime();
                long delay = (nowTime - startTime) - (allTimes - mTimes) * mCountDownInterval;
                // 处理跳秒
                while (delay > mCountDownInterval){
                    mTimes --;
                    if (mCallBack != null){
                        mCallBack.onTick(mTimes);
                    }

                    delay -= mCountDownInterval;
                    if (mTimes <= 0){
                        finishCountDown();
                        return;
                    }
                }

                mHandler.postDelayed(this, 1000 - delay);
            }else {
                finishCountDown();
            }
        }
    };

    private void finishCountDown(){
        if (mCallBack != null){
            mCallBack.onFinish();
        }
        isStart = false;
    }

    public void cancel(){
        mHandler.removeCallbacksAndMessages(null);
        isStart = false;
    }

    public interface OnTimerCallBack{

        void onStart();

        void onTick(int times);

        void onFinish();

    }

}

思路就是在倒计时开始前获取一次SystemClock.elapsedRealtime(),每轮倒计时再获取一次SystemClock.elapsedRealtime()相减得到误差,根据delay校准。然后使用while循环来处理跳秒的操作,与原生的CountDownTimer不同,这里如果跳了多少秒,就会返回多少次回调。

文章出自www.jianshu.com/p/f1b63b212… 当然也是自己写的,是同一个号,只是最近打算转平台

作者:流浪汉kylin
链接:https://juejin.cn/post/7140652166980567076
更多Android学习资料可点击下方卡片了解~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio倒计时计时器的源码可以通过以下步骤实现: 1. 创建一个新的Android项目并在MainActivity中添加一个TextView组件,用于显示倒计时。 2. 在MainActivity中定义一个计时器变量、计时时长和显示倒计时的TextView。 3. 在onCreate()方法中初始化计时器变量,以及获取TextView组件的引用。 4. 在onStart()方法中启动计时器,并使用适当的间隔(例如1秒)更新显示倒计时的TextView内容。同时,设置计时器的总时长。 这里是源码示例: ``` import android.os.Bundle; import android.os.CountDownTimer; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private CountDownTimer countDownTimer; private long timeLeftInMillis = 300000; // 总时长为5分钟 private TextView countdownTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); countdownTextView = findViewById(R.id.countdownTextView); countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) { @Override public void onTick(long millisUntilFinished) { timeLeftInMillis = millisUntilFinished; updateCountdownText(); } @Override public void onFinish() { // TODO: 计时器结束时的操作 } }; countDownTimer.start(); } @Override protected void onStart() { super.onStart(); countDownTimer.start(); } private void updateCountdownText() { int minutes = (int) (timeLeftInMillis / 1000) / 60; int seconds = (int) (timeLeftInMillis / 1000) % 60; String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); countdownTextView.setText(timeLeftFormatted); } } ``` 上述代码在MainActivity中创建了一个CountDownTimer对象并在onCreate()方法中启动了计时器。在onTick()方法中更新了倒计时显示的TextView,并在onFinish()方法中定义计时器结束时的操作。updateCountdownText()方法可将剩余的毫秒数转换为分钟和秒,并将其格式化为“分:秒”的形式。 以上是一个简单的Android Studio倒计时计时器的源码示例。你可以根据自己的需求进一步扩展和定制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值