案例2——hprof文件显示出Fragment内存泄漏
接下来我们来看fragment内存泄漏,老规矩查看fields和references,确保它符合内存泄漏的情形;我们点击jump to source查看泄漏的位置
Fragment#MZBannerView#内部类Runnbale
/**
* Banner 切换时间间隔
*/
private int mDelayedTime = 5000;
private final Runnable mLoopRunnable = new Runnable() {
@Override
public void run() {
if (mIsAutoPlay) {
mCurrentItem = mViewPager.getCurrentItem();
mCurrentItem++;
if (mCurrentItem > mAdapter.getCount() - 1) {
mCurrentItem = 0;
mViewPager.setCurrentItem(mCurrentItem, false);
mHandler.postDelayed(this, mDelayedTime);
} else {
mViewPager.setCurrentItem(mCurrentItem);
mHandler.postDelayed(this, mDelayedTime);
}
} else {
mHandler.postDelayed(this, mDelayedTime);
}
}
};
可以看到Fragment内存泄漏的第一个原因,内部类runnable持有了view的实例,每个Runnbale会发送一个延时5秒的消息,消息发送期间,有可能view、fragment已经结束了生命周期,此时产生了内存泄漏。
解决办法也很简单,view离开窗口的时候,释放Handler中消息,释放Runnbale对view 的引用。
- 静态Runnbale内部类+对view的弱引用(此部分代码与前面的示例很相似,不重复贴代码了)
- 离开窗口remove#handler消息
view对Activity暴露了pause方法,在Activity销毁时,强制清空handler的任务;
// view代码
/**
* 停止轮播
*/
public void pause() {
mIsAutoPlay = false;
mHandler.removeCallbacks(mLoopRunnable);
mBannerPageClickListener = null;
}
// Activity代码:
@Override
public void onDestroy() {
super.onDestroy();
dataBing.homeBanner.pause();
}