android引导界面倒计时的实现(CountDownTimer)

app 一般都会有倒计时功能,无论是引导页面,还是短信验证码填写。本文便讲解下简单的实现。

效果图

在这里插入图片描述

分析

这个小小的倒计时功能也有一些技巧,特别是对于初学者来说可能就是坑,比如你在ui线程进行倒计时10秒。不好意思 app crash,主线程不能进行耗时操作,这时我们又想到了Handler,Timer一些类。

实现1

自己封装 < . . >

既然能写这个界面,那么相信你一定是入门界别的了,不说读过handler 源码,肯定会使用Handler,自己看看网上思路也可以尝试封装下一个自己的计时器倒计时。当时我也是傻傻的自己封装了一个哈,还是对api掌握的不够了解,原来google工程师为我们提供的就有。

实现2 CountDownTimer

系统源码实现(可以忽略不看,参考下面的具体使用即可):

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

/**
 * Schedule a countdown until a time in the future, with
 * regular notifications on intervals along the way.
 *
 * Example of showing a 30 second countdown in a text field:
 *
 * <pre class="prettyprint">
 * new CountDownTimer(30000, 1000) {
 *
 *     public void onTick(long millisUntilFinished) {
 *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
 *     }
 *
 *     public void onFinish() {
 *         mTextField.setText("done!");
 *     }
 *  }.start();
 * </pre>
 *
 * The calls to {@link #onTick(long)} are synchronized to this object so that
 * one call to {@link #onTick(long)} won't ever occur before the previous
 * callback is complete.  This is only relevant when the implementation of
 * {@link #onTick(long)} takes an amount of time to execute that is significant
 * compared to the countdown interval.
 */
public abstract class CountDownTimer {

    /**
     * Millis since epoch when alarm should stop.
     */
    private final long mMillisInFuture;

    /**
     * The interval in millis that the user receives callbacks
     */
    private final long mCountdownInterval;

    private long mStopTimeInFuture;
    
    /**
    * boolean representing if the timer was cancelled
    */
    private boolean mCancelled = false;

    /**
     * @param millisInFuture The number of millis in the future from the call
     *   to {@link #start()} until the countdown is done and {@link #onFinish()}
     *   is called.
     * @param countDownInterval The interval along the way to receive
     *   {@link #onTick(long)} callbacks.
     */
    public CountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

    /**
     * Cancel the countdown.
     */
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    /**
     * Start the countdown.
     */
    public synchronized final CountDownTimer start() {
        mCancelled = false;
        if (mMillisInFuture <= 0) {
            onFinish();
            return this;
        }
        mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }


    /**
     * Callback fired on regular interval.
     * @param millisUntilFinished The amount of time until finished.
     */
    public abstract void onTick(long millisUntilFinished);

    /**
     * Callback fired when the time is up.
     */
    public abstract void onFinish();


    private static final int MSG = 1;


    // handles counting down
    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 {
                    long lastTickStart = SystemClock.elapsedRealtime();
                    onTick(millisLeft);

                    // take into account user's onTick taking time to execute
                    long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
                    long delay;

                    if (millisLeft < mCountdownInterval) {
                        // just delay until done
                        delay = millisLeft - lastTickDuration;

                        // special case: user's onTick took more than interval to
                        // complete, trigger onFinish without delay
                        if (delay < 0) delay = 0;
                    } else {
                        delay = mCountdownInterval - lastTickDuration;

                        // special case: user's onTick took more than interval to
                        // complete, skip to next interval
                        while (delay < 0) delay += mCountdownInterval;
                    }

                    sendMessageDelayed(obtainMessage(MSG), delay);
                }
            }
        }
    };
}

可以看出 源码内部使用Handler 已经帮我们实现好了,我们只需要使用几个方法即可。

使用解释

1 、首先CountDownTimer是一个抽象类我们可以像使用点击事件那样直接以匿名内部类方式使用。或者我们写个类继承此抽象类也行。
2 、 构造

 public CountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

参数1 倒计时总时间
参数2 倒计时时间间隔

3、 抽象方法
onTick 在这处理倒计时期间相关逻辑
onFinish 在这处理 倒计时结束工作

4 、不要忘记的重要一点 通过start()方法开启任务

5、代码规范
在 acyivity fragment dialog相关中使用一定要留意空指针或者内存泄漏避免(参看代码实现)。具体引起原因参考handler引起内存泄漏的原因。

6、简单使用参考

package com.example.administrator.modelmall.ui.activities;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.CountDownTimer;
import android.support.v7.widget.AppCompatTextView;
import android.view.View;

import com.example.administrator.modelmall.R;

import butterknife.BindView;

/**
 * Create by SunnyDay on 2019/03/15
 */
public class CountDownActivity extends BaseActivity {
    @BindView(R.id.tv_count_down)
    AppCompatTextView countDownText;
    private CountDownTimer timer;

    @Override
    public Object offerLayout() {
        return R.layout.activity_countdown;
    }

    @Override
    public void onBindView() {
        setNoTitleBarAndFullScreen();
        initCountDown();
    }


    /**
     * 倒计时逻辑处理
     */
    private void initCountDown() {
        // 避免内存泄漏
        if (!isFinishing()) {
            timer = new CountDownTimer(1000 * 10, 1000) {
                @SuppressLint("SetTextI18n")
                @Override
                public void onTick(long millisUntilFinished) {
                    countDownText.setEnabled(true);
                    countDownText.setText((int) millisUntilFinished / 1000 + " 跳过");
                    countDownText.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            startActivity(new Intent(CountDownActivity.this, GuideActivity.class));
                            finish();
                        }
                    });
                }

                @Override
                public void onFinish() {
                    startActivity(new Intent(CountDownActivity.this, GuideActivity.class));
                    finish();
                }
            }.start();
        }

    }

    @Override
    public void destory() {
        // 避免内存泄漏
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

8、参考

小结

简单的分享下使用吧 溜了。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值