导航

本文为原创文章,欢迎转载,但请注明出处http://www.cnblogs.com/yexiubiao/archive/2013/01/02/2842026.html,未在文章页面明显位置给出原文连接的,将保留追究法律责任的权利。
 
在开发中可能我们会遇到这样的需求,
1,界面上有一个倒计时,当倒计时间剩下不多时,时间开始闪动(颜色红白交替)。如下图:
 
2,当时间马上就要结束时,闪动频率加快,如图(截图后有些不流畅,实际运行时很流畅的):
 
 
关于需求1,我们用android自带的倒计时类CountDownTimer很简单地实现,只需要实现抽象类CountDownTimer的两个抽象方法onTick()和onFinish()即可,颜色的话可以用一个标志flag控制交替改变。
代码:
//3分钟后到时,每1秒回调一次onTick()
new CountDownTimer(3 * 60 * 1000, 1000) {
    @Override
    public void onTick(long millisUntilFinished) {
        //在这里改变界面上的时间
    }
 
    @Override
    public void onFinish() {
        //在这里处理时间到了的逻辑
    }
}.start();

 

 
关于需求2,实现起来有点麻烦。
首先看下CountDownTimer的构造方法:
public CountDownTimer(long millisInFuture, long countDownInterval)
构造CountDownTimer时需传入两个参数,millisInFuture表示倒计时的时长,countDownInterval表示回调间隔(频率)。每隔countDownInterval秒会回调一次onTick()方法。我们马上想到的是 CountDownTimer应该有个setCountDownInterval()方法,可以改变回调间隔countDownInterval的值。但是看了CountDownTimer的源码后,没有发现任何可以改变countDownInterval值的方法。而且成员变量mCountdownInterval是私有的。
 
这时候我们可能想到以下几种实现方案。
方案1:当时间小于指定值时,设置一个标志flag,实现类根据这个flag,重新new一个CountDownTimer,并指定新的回调间隔值countDownInterval。但这样实现起来很麻烦,每new一次倒计时,都得实现CountDownTimer的抽象方法,如果项目中有n个地方用到倒计时,那就得重新写n次,不可取。
 
方案2:构造CountDownTimer类的时候传入的countDownInterval值改为原来的一半,然后在代码中控制,如果是正常显示状态则每隔两次调用一次onTick()方法,当需要加快回调间隔时,每隔一次回调一次onTick()方法,不过这样不太灵活,回调间隔只能是原来的整数倍。而且还得控制标志位flag,也不太可取。
 
方案3:反射,利用反射动态地改变CountDownTimer类的私有字段mCountdownInterval,这里我抽取成了一个方法,代码如下:
privatevoid changeCountdownInterval(long time) {
    try {
    // 反射父类CountDownTimer的mCountdownInterval字段,动态改变回调频率
    Class clazz = Class.forName("android.os.CountDownTimer");
    Field field = clazz.getDeclaredField("mCountdownInterval");
    field.setAccessible(true);
    field.set(this, time);
    } catch (Exception e) {
        Log.e("Ye", "反射类android.os.CountDownTimer失败: " + e);
    }
}

 

总结,用方案3的反射实现起来很灵活而且简单,不好的地方是,反射一般尽量少用,因为既然源码将mCountdownInterval定义为私有,而且不暴露修改他的值的方法,就一定有他的原因,以后源码可能会修改私有字段和私有方法,造成反射失效。不过在这里实现方法比较简单灵活,权衡了一下,还是可以使用,最后附上demo ^_^。
 https://files.cnblogs.com/yexiubiao/YeCountDownTimer.rar