Handler和它的朋友们(流程、内存泄露相关)

本文深入解析了Android消息机制的工作流程,包括Looper、Handler与MessageQueue之间的交互原理,以及由此可能引发的内存泄露问题。并提供了两种有效解决方案。

流程:

1.Looper.prepare()

为当前线程set一个Looper(通过ThreadLocal.set方法)

新创建的Looper里面有一个MessageQueue的成员变量

173516_rWpX_1029054.png

220923_H4tC_1029054.png

2.Handler handler = new Handler();

handler得到一个当前线程的Looper对象(通过ThreadLocal.get方法),从而得到Looper的MessageQueue对象

173537_86MP_1029054.png

173541_nmWM_1029054.png

Looper:

173547_F5oI_1029054.png

173524_bHOn_1029054.png

3.Looper.loop()

死循环将MessageQueue里面的Message对象交给handler处理

//因为这个方法里面有个死循环,Looper.loop()后面的代码不能被执行。

173554_Daw3_1029054.png

173610_MafP_1029054.png

173615_tqVy_1029054.png

msg.target.dispatchMessage(msg); //此方法就是将message分配到Handler处理

 

 

4.handler.sendMessage

将这个Message进行入队操作(通过创建Handler时得到MessageQueue对象)

173621_IP40_1029054.png

173625_NccW_1029054.png

 

 

内存泄露

This Handler class should be static or leaks might occur问题

如果在一个Activity或者其他类中定义了一个Handler的非静态内部类,AndroidStudio会出现以下提示:

173632_NPSW_1029054.png

原因:

1.非静态的内部类持有其外部类的引用,所以这里的Handler内部类持有Activity的引用。

2.从上面第四步可以看出:handler.sendMessage方法会调用enqueueMessage,enqueueMessage方法会让发送的message对象持有当前的Handler的引用(看标注1)。

引用链如下图

173637_TvEv_1029054.png

3.如果Activity调用finish时,Handler的MessageQueue中还有未处理的Message,这个Message持有Handler的引用,Handler持有Activity的引用,这样会使得Activity不能被回收,而引起内存泄露,直到所有的MessageQueue中的Message处理完毕(Message的recycleUnchecked方法会使target置空(看标注2),Message不再持有Handler的引用)。

另外如果调用的是sendMessageDelayed,那么在delay到达前,message也会一直持有handler的引用,此时Activity调用finish,Activity也是不能被回收。

还有一种情况就是,耗时任务的线程(下载图片)持有handler的引用(sendMessage通知主线程进度),Activity调用finish时,耗时任务线程没执行完毕,Activity也不能被回收。

173642_GaPw_1029054.png

 

解决办法:

1.将Handler改为静态内部类,构造方法传进Activity,并定义为弱引用

 

2.在Activity onDestory方法调用

handler.removeCallbacksAndMessages(null);

但这种只能解决Message引用Handler,Handler引用Activity这种情况。

 

转载于:https://my.oschina.net/stphwn/blog/1813694

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值