Handler使用不当导致泄漏
场景
Fragment生命周期结束后没有及时remove message,导致Fragment无法释放
handler.postDelay(runnable, 2000)
自定义Handler
Handler匿名内部类持有Fragment或者Activity
Message
处理方式
解决办法是Fragment/Activity销毁时清空消息队列 mHandler.removeCallbacksAndMessages(null);
或者内部类使用WeakReference弱引用Fragment/Activity
引用链原理
当Activity/Fragment销毁时,Looper所在线程(GC Root)通过Looper.loop()开启了一个死循环,在不断从消息队列MessageQueue中取出消息,在Framgent/Activity中postDelay发送的消息被添加到消息队列, 入队时,Handler会被设置给Message.target字段,
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// 引用发送消息的Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
....
return queue.enqueueMessage(msg, uptimeMillis);
}
postDelay函数会将Runnable设置到Message.callback字段
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}所以不管是post了一个内部类的Runnable还是,Handler本身是内部类,假设此Message作为延迟消息,将会一直存在消息队列中,由于GC root的引用从而导致Message持有的callback或者target指向的handler无法释放,其持有的Fragment也无法被回收,导致内存泄漏