记录:关于匿名Handler内存泄露问题

RT:

在Inspect Code中发现了某个内存泄露的提示


提示在这个Activity类中可能存在内存泄露,代码如下


常规的Handler写法,此处看的有点蒙,为什么会有内存泄露,于是度娘查了一下。

当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用,这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致Activity被持有引用而无法被回收

在查明原因后,有两种解决方案,如下:

1、通过程序逻辑来进行保护,即removeCallbacks()方法去移除消息队列中的消息。

2、将Handler声明成静态类,代码如下:

private static class MyHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
    }
}
将Handler如此声明后,会发现程序不能在这里面操作Activity对象了,所以需要在Handler中创建一个Activity的弱引用(WeakReference),不明白的请自行百度WeakReference,此时代码如下:

private static class MyHandler extends Handler{
    private final WeakReference mActivity;
    public MyHandler (AsynTaskListActivity activity){
        mActivity = new WeakReference(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        AsynTaskListActivity activity = mActivity.get();
        if (activity != null) {
            switch (msg.what){
                 code...
            }
        }
    }
}
如此大功告成!!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章