CountDownTimer未回收导致的内存泄漏

最近有版本开发,加班到有空就想躺床上。总算有空余时间,来找找项目中的内存泄漏问题。

 

CountDownTimer未回收导致的内存泄漏_第1张图片

 

这是在登录页面出现的问题,出问题的是获取验证码倒计时控件出现的。其实这个内存泄漏很久之前就发现过,但是总是有时出现,有时有不出现。其实是因为在测试和开发环境中,直接使用的是默认的验证码,只是有时手抖会点到会出现这个。从错误信息中可以看出来,就是CountDownTimer导致的内存泄漏。

通过查找代码,发现VercCodeButton自定义view中,只开启了CountDownTimer,但是并没有调用停止CountDownTimer的方法

 

/**
 * 60s倒计时
 */
private void initCountDown() {
    downTimer = new CountDownTimer(AppConfig.COUNTDOWN, AppConfig.COUNTDOWNINTERVAL) {

        @Override
        public void onTick(long millisUntilFinished) {
            isCountDown = true;
            setText(millisUntilFinished / AppConfig.COUNTDOWNINTERVAL + "s");
            setEnableColor(false);

        }

        @Override
        public void onFinish() {
            isCountDown = false;
            setText("重新发送");
            setEnableColor(true);
        }
    };
    downTimer.start();
}

 

先看下countdownTimer中的入口

/**
 * 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;
}

11行可以看到,是通过handler来进行调度的,找到handler的代码

// 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,从handleMessage方法中可以看到,判断的地方,在没有消耗完mStopTimeInFuture 值之前,每次都会重新发一条handler消息。但是,大部分时间,在登录页面都是在倒计时还没用完就会销毁页面,这时CountDownTimer内部还在发送消息,这样就会持有当前页面,当需要回收时,会出现引用数导致回收不了当前页面出现泄漏。就是常说的handler的内存泄漏。

 

其实要解决也很简单,在CountDownTimer内部已经提供了回收方法

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

我们只需要在页面销毁的时候调用CountDownTimer的cancel方法就能够避免这种问题

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

 

 

 

 

 

你可能感兴趣的:(CountDownTimer未回收导致的内存泄漏)