解决安卓倒计时 CountDownTimer类 内存泄漏
2020-03-25 本文已影响0人
唐小鹏
项目集成了leakCanary在进入开户页面总是报内存泄漏,找了找,原来是CountDownTimer导致
现在直接给出修改后的方案
CountDownTimerUtils mCountDownTimerUtils = null; //写到外面,全局变量方便退出的时候销毁
点击控件的地方
if (mCountDownTimerUtils == null) {
mCountDownTimerUtils = new CountDownTimerUtils(tvGetVeri, 60000, 1000);
}
mCountDownTimerUtils.start();
其实不难发现,CountDownTimer的原理还是用到了Handler,所以很容易造成内存泄漏问题,当Activity或者Fragment关闭而倒计时还未结束的时候,会在后台一直执行,而很多时候我们用倒计时会有更新UI的操作,而控件都持有activity的引用,长期得不到释放的话就会造成内存泄漏,不仅需要控件执有弱引用,也需要在activity或fragment销毁的时候调用cancle方法。
// 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);
}
}
}
};
写一个工具类继承CountDownTimer,注意textview需要弱引用
public class CountDownTimerUtils extends CountDownTimer {
private WeakReference<TextView> mTextView;//显示倒计时的文字 用弱引用 防止内存泄漏
public CountDownTimerUtils(TextView textView, long millisInFuture, long countDownInterval) {
//countDownInterval:每次的间隔时间 单位都是毫秒
super(millisInFuture, countDownInterval);
this.mTextView = new WeakReference(textView);
}
@Override
public void onTick(long millisUntilFinished) {
//用弱引用 先判空 避免崩溃
if (mTextView.get() == null) {
cancle();
return;
}
mTextView.get().setClickable(false); //设置不可点击
mTextView.get().setText(millisUntilFinished / 1000 + getResources().getString(R.string.get_code_s)); //设置倒计时时间
mTextView.get().setTextColor(getResources().getColor(R.color.color_common_normal));
}
@Override
public void onFinish() {
//用软引用 先判空 避免崩溃
if (mTextView.get() == null) {
cancle();
return;
}
mTextView.get().setText(getResources().getString(R.string.restart_get_code));
mTextView.get().setClickable(true);//重新获得点击
mTextView.get().setTextColor(getResources().getColor(R.color.color_4D8CF5));
}
public void cancle() {
if (this != null) {
this.cancel();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 写为全局变量是为了这里用
if (mCountDownTimerUtils != null) {
mCountDownTimerUtils.cancel();
mCountDownTimerUtils = null;
}
}