欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中CountDownTimer类详解

程序员文章站 2022-03-05 14:17:24
一、概述项目中经常用到倒计时的功能,比如说限时抢购,手机获取验证码等等。而google官方也帮我们封装好了一个类:countdowntimer,使我们的开发更加方便;二、apicountdowntim...

一、概述

项目中经常用到倒计时的功能,比如说限时抢购,手机获取验证码等等。而google官方也帮我们封装好了一个类:countdowntimer,使我们的开发更加方便;

二、api

countdowntimer是一个抽象类,有两个抽象方法,它的api很简单

public abstract void ontick(long millisuntilfinished);//这个是每次间隔指定时间的回调,millisuntilfinished:剩余的时间,单位毫秒
public abstract void onfinish();//这个是倒计时结束的回调

使用的时候只需要

new countdowntimer(long millisinfuture, long countdowninterval)
//millisinfuture:倒计时的总时长
//countdowninterval:每次的间隔时间  单位都是毫秒

三、基本使用方法

我们以短信验证码的倒计时来看,点击获取验证码,倒计时60s不可点击

new countdowntimer(60 * 1000, 1000) {
    @override
    public void onfinish() {
        if (tvcode != null) {
            tvcode.settext("重新获取");
            tvcodewr.settextcolor(color.parsecolor("#e94715"));
            tvcode.setclickable(true);
            tvcode.setenabled(true);
        }

        cancel();
    }

    @override
    public void ontick(long millisuntilfinished) {
        if (tvcode != null) {
            tvcode.setclickable(false);
            tvcode.setenabled(false);
            tvcode.settext(millisuntilfinished / 1000 + "s");
            tvcode.settextcolor(color.parsecolor("#999999"));
        }
    }
}.start();

点击按钮,获取验证码成功之后就可以执行以上操作,最后一定要start,不然不会执行

四、使用注意

countdowntimer使用很简单,但是坑很多,需要注意避免踩坑。

1、空指针:

如果在activity或者fragment关闭销毁的时候没有调用cancle方法,它的ontick方法还是会继续执行,这个时候ui控件都为空,不注意判断的话很容易空指针

2、时间不是太准的问题:

我们看countdowntimer的源码可以看到,在执行ontick的方法时,google源码里面减去了程序执行到这里的时候所消耗的时间,这里可以看出google代码的严谨

final long millisleft = mstoptimeinfuture - systemclock.elapsedrealtime();

if (millisleft <= 0) {
    onfinish();
} else if (millisleft < mcountdowninterval) {
    // no tick, just delay until done
    sendmessagedelayed(obtainmessage(msg), millisleft);
}

所以一开始倒计时的时间是59,这里可以在构造方法里面稍微加一点时间就可以解决如:

new countdowntimer(60 * 1000+300, 1000)

3、内存泄漏问题

首先我们来看源码,核心代码如下

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) {
                // no tick, just delay until done
                sendmessagedelayed(obtainmessage(msg), millisleft);
            } else {
                long lasttickstart = systemclock.elapsedrealtime();
                ontick(millisleft);

                // take into account user's ontick taking time to execute
                long delay = lasttickstart + mcountdowninterval - systemclock.elapsedrealtime();

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

                sendmessagedelayed(obtainmessage(msg), delay);
            }
        }
    }
};

可以看到countdowntimer的原理还是用到了handler,所以很容易造成内存泄漏问题,当activity或者fragment关闭而倒计时还未结束的时候,会在后台一直执行,而很多时候我们用倒计时会有更新ui的操作,而控件都持有activity的引用,长期得不到释放的话就会造成内存泄漏,甚至会造成1所说的空指针问题,所以一般要在activity或fragment销毁的时候调用cancle方法。

我自己把这个进行了封装,写成了一个工具类以供参考:

public class timeutils {
    private string color;//这里可以修改文字颜色
    weakreference<textview> tvcodewr;//控件软引用,防止内存泄漏
    private countdowntimer timer;


    public timeutils(textview tvcode, string color) {
        super();
        this.tvcodewr = new weakreference(tvcode);
        this.color = color;
    }
//这是倒计时执行方法
    public void runtimer() {
        timer = new countdowntimer(60 * 1000 - 1, 1000) {
            @override
            public void onfinish() {
                if (tvcodewr.get() != null) {
                    tvcodewr.get().settext("重新获取");
                    tvcodewr.get().settextcolor(color.parsecolor(color));
                    tvcodewr.get().setclickable(true);
                    tvcodewr.get().setenabled(true);
                }

                cancel();
            }

            @override
            public void ontick(long millisuntilfinished) {
                if (tvcodewr.get() != null) {
                    tvcodewr.get().setclickable(false);
                    tvcodewr.get().setenabled(false);
                    tvcodewr.get().settext(millisuntilfinished / 1000 + "s");
                    tvcodewr.get().settextcolor(color.parsecolor("#999999"));
                }
            }
        }.start();
    }
//这个方法可以在activity或者fragment销毁的时候调用,防止内存泄漏
    public void cancle() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

到此这篇关于android中countdowntimer类详解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。