一、简介
DialogFragment是Android3.0之后引入的一种特殊的Fragment,官方建议使用DialogFragment代替Dialog或者AllertDialog来实现弹框的功能,因为它可以更好的管理Dialog的生命周期以及可以更好复用。
二、使用中遇到内存泄露
在使用过程中,由于业务需要对DialogFragment的dismiss事件进行了监听,在DialogFragment展示与消失的时候,经常会出现LeakCanary检测的内存泄露问题。查看LeakCanary的内存泄露引用链如下图所示:
image.png
这里只贴出了一张图,LeakCanary每次报出来的引用链并不完全相同,图上中显示的是RxJava的ThreadHandler,有的则显示的是高德地图的ThreadHandler(amapLocManagerThread),由此猜测这里并不是主线程的ThreadHandler引起的内存泄露,而是第三方库中的ThreadHandler引起的内存泄露。但总的来说都是HandlerThread中处理的Message引用了NormalTitleBgDialog(DialogFragment)不能被释放。下面具体分析一下出现这个问题的原因。
三、原因分析
那么Message是怎么引用到DialogFragment的呢?在DialogFragment中搜索一下Message一无所获。DialogFragment实际是Dialog的封装,在Dialog中搜索Message试试,果然发现Dialog的Cancle和Dismiss都是通过Handler进行操作的,从这里入手分析一下内存泄露的原因:
DialogFragment中的onActivityCreated
Cancle和Dismiss的监听传入的是DialogFragment实现的两个接口:DialogInterface.OnCancelListener, DialogInterface.OnDismissListener
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDialog.setOnCancelListener(this);
mDialog.setOnDismissListener(this);
}
setOnDismissListener
这里会通过mListenerHandler获取到一个mDismissMessage对象。
public void setOnDismissListener(@Nullable OnDismissListener listener) {
if (listener != null) {
mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);
} else {
mDismissMessage = null;
}
}
public void setOnCancelListener(@Nullable OnCancelListener listener) {
if (listener != null) {
mC