一,概述

在项目开发中经常会用到倒计时这个功能,而Android也帮我们封装好了一个类CountDownTimer,给我们的开发带来了很大的方便;

二,API

CountDownTimer (long millisInFuture, long countDownInterval)参数1,设置倒计时的总时间(毫秒)参数2,设置每次减去多少毫秒

三,基本用法

以App中获短信取验证码为例:

    private Button btn;    private TextView vertifyView;      @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        initView();    }    private void initView(){        vertifyView =(TextView) findViewById(R.id.vertifyView);        btn =(Button) findViewById(R.id.button);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //1,请求后台...                //2,触发定时器刷新UI(启动代码最好放在请求后台回调成功之后)                timer.start();            }        });    }    private CountDownTimer timer = new CountDownTimer(10000, 1000) {          @Override          public void onTick(long millisUntilFinished) {              vertifyView.setText((millisUntilFinished / 1000) + "秒后可重发");          }          @Override          public void onFinish() {              vertifyView.setEnabled(true);              vertifyView.setText("获取验证码");          }      };  

ok~这样一个基本的CountDownTimer案例就完成了

四,存在的问题

CountDownTimer如果使用不当,常常会报空指针异常,甚至造成严重的内存泄漏
5.0源码:

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 if (millisLeft < mCountdownInterval) {                    // 剩余时间小于一次时间间隔的时候,不再通知,只是延迟一下                    sendMessageDelayed(obtainMessage(MSG), millisLeft);                } else {                    long lastTickStart = SystemClock.elapsedRealtime();                    onTick(millisLeft);                     // 处理用户onTick执行的时间                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();                     // 特殊情况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次interval                    while (delay < 0) delay += mCountdownInterval;                    sendMessageDelayed(obtainMessage(MSG), delay);                }            }        }    };}

从源码中我们可以看出,CountDownTimer的内部实现是采用Handler机制,通过sendMessageDelayed延迟发送一条message到主线程的looper中,然后在自身中收到之后判断剩余时间,并发出相关回调,然后再次发出message的方式。

这样的方式其实是有一定弊端的,那就是如果在Activity或者Fragment被回收时并未调用CountDownTimer的cancel()方法结束自己,这个时候CountDownTimer的Handler方法中如果判断到当前的时间未走完,那么会继续调用

sendMessageDelayed(obtainMessage(MSG), delay);

触发

onTick(millisLeft);

当回调了Activity或者fragment中CountDownTimer的onTick方法时,Activity或者Fragment已经被系统回收,从而里面的变量被设置为Null,再调用

vertifyView.setText((millisUntilFinished / 1000) + "秒后可重发");  

vertifyView为空,也就空指针了~
同时,CountDownTimer中的Handler方法还在继续执行,这一块空间始终无法被系统回收也就造成了内存泄漏问题。

五,总结

1,在CountDownTimer的onTick方法中记得判空

activity中    if(!activity.isFinishing()){        //doing something...    }fragment中    if(getActivity()!=null){       //doing something...    }

2,在配合DialogFragment使用时,如果在onFinish()方法调用了 dismiss()方法让弹框消失,记得 判断getFragmentManager是否为空

    @Override    public void onFinish() {        if(getFragmentManager()!=null){            dismiss();        }    }

3,在使用CountDownTimer时,在宿主Activity或fragment生命周期结束的时候,记得调用timer.cancle()方法

@Override    public void onDestroy() {        if(timer!=null){            timer.cancel();            timer = null;        }        super.onDestroy();    }

遇到问题还是尽量先从控件的源码中寻找答案~相信源码是最好的老师O(∩_∩)O哈哈~

更多相关文章

  1. Android中Notification的framework层讲解【安卓源码解析四】
  2. Android ListView动画实现方法
  3. ADB连接Android设备的三种方法
  4. [Android设计模式]Android退出应用程序终极方法
  5. Android通过Alpha实现渐变效果的几个方法
  6. Android中AVD(Android Virtual Device)不能启动的处理方法
  7. Android多个Activity切换时其生命周期中的方法执行顺序

随机推荐

  1. Android通过http协议POST传输方式
  2. Android常用功能代码总结一
  3. android通过程序收起通知栏
  4. android发送restful风格的http请求
  5. android之wifi体系架构源码流程分析
  6. android中的两端对齐
  7. 安卓巴士Android开发神贴整理
  8. android 隐藏ListView滚动条
  9. Android(安卓)Notification的使用
  10. Android问题总结