关于HandlerLeak的一点理解
2015-01-17 18:35
288 查看
之前很多代码是这样写的:
在应用程序线程的MessageQueue中排队的Message对象还保留他们的目标Handler。如果Handler是一个内部类(注:无论是匿名还是非匿名,匿名是比较常见用法),它的外部类将被保留(至于为什么,请参考Java嵌套类相关说明)。为了避免泄漏外部类,声明一个Handler子类为静态内部类(注:这样就避免了Handler对象对外部类实例的自动引用),其内部持有一个对外部类对象的WeakReference。
再分析一下这几个泄漏问题:(1)排队中的Message对象对Handler的持有导致泄漏;(2)Handler对象对外部类(如Activity或Service)实例的强引用持有。
方案:(1)针对第1个原因,在使用Handler的组件生命周期结束前清除掉MessageQueue中的发送给Handler的Message对象(例如在Activity或Service的onDestroy()中调用Handler的remove*方法);(2)针对第2个原因,Handler的实现类采用静态内部类的方式,避免对外部类的强引用,在其内部声明一个WeakReference引用到外部类的实例。
关于Handler的remove*方法,这儿介绍一下(可以参考源码或文档)
removeCallbacks(Runnable r) ——清除r匹配上的Message。
removeCallbacks(Runnable r, Object token) ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
removeCallbacksAndMessages(Object token) ——清除token匹配上的Message。
removeMessages(int what) ——按what来匹配
removeMessages(int what, Object object) ——按what来匹配
我们更多需要的是清除以该Handler为target的所有Message(包括Callback),那么调用如下方法即可
handler.removeCallbacksAndMessages(null);
最终代码像这个样子:
@SuppressLint("HandlerLeak") Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case HyyConstants.REFRESH_LIST: Toast.makeText( HyyDLApplication.getContext().getApplicationContext(), "Refresh list", Toast.LENGTH_SHORT).show(); initList(); break; default: break; } }; };这样做有一个好处是可以在Handler里触发Activity的操作。但也造成了内存泄漏的隐患。隐患是这样形成的:
在应用程序线程的MessageQueue中排队的Message对象还保留他们的目标Handler。如果Handler是一个内部类(注:无论是匿名还是非匿名,匿名是比较常见用法),它的外部类将被保留(至于为什么,请参考Java嵌套类相关说明)。为了避免泄漏外部类,声明一个Handler子类为静态内部类(注:这样就避免了Handler对象对外部类实例的自动引用),其内部持有一个对外部类对象的WeakReference。
再分析一下这几个泄漏问题:(1)排队中的Message对象对Handler的持有导致泄漏;(2)Handler对象对外部类(如Activity或Service)实例的强引用持有。
方案:(1)针对第1个原因,在使用Handler的组件生命周期结束前清除掉MessageQueue中的发送给Handler的Message对象(例如在Activity或Service的onDestroy()中调用Handler的remove*方法);(2)针对第2个原因,Handler的实现类采用静态内部类的方式,避免对外部类的强引用,在其内部声明一个WeakReference引用到外部类的实例。
关于Handler的remove*方法,这儿介绍一下(可以参考源码或文档)
removeCallbacks(Runnable r) ——清除r匹配上的Message。
removeCallbacks(Runnable r, Object token) ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
removeCallbacksAndMessages(Object token) ——清除token匹配上的Message。
removeMessages(int what) ——按what来匹配
removeMessages(int what, Object object) ——按what来匹配
我们更多需要的是清除以该Handler为target的所有Message(包括Callback),那么调用如下方法即可
handler.removeCallbacksAndMessages(null);
最终代码像这个样子:
相关文章推荐
- 关于BMP图片的一点理解,读取图象数据到数组
- 关于反射的一点理解(一)
- 关于DataRow和DataColumn的一点个人简单理解
- us/os ii 学习笔记 20100421 关于os的一点宏观理解
- 关于AS3中弱引用的一点理解(转载)
- 关于DataRow和DataColumn的一点个人简单理解
- 关于Action的一点理解
- 我的一点浅见——关于机器的理解
- 一个草根关于OO的一点理解
- 关于AS3中弱引用的一点理解
- 关于equals()和==操作的一点理解
- 关于DataRow和DataColumn的一点个人简单理解-.NET教程,数据库应用
- 关于KMP算法的一点个人理解
- 关于龙芯拿MIPS授权的一点理解
- 关于openlayers中namespace的一点理解
- 关于Ndis驱动的一点个人理解
- 关于AS3中弱引用的一点理解
- 关于DataRow和DataColumn的一点个人简单理解
- 关于博弈论中的共同知识的一点理解
- 关于unix下实际用户ID、有效用户ID、设置用户ID、文件所有者ID的一点理解