避免Handler内存泄漏

2017-05-12  本文已影响57人  Stephen__Li

Handler也是造成内存泄露的一个重要的源头,主要Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的,Handler引用Activity会存在内存泄露。

public class HandlerActivity extends Activity {  
  
    private final Handler mHandler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            // ...  
        }  
    };  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 60000);  
  
        //just finish this activity  
        finish();  
    }  
  
}  

是否您以前也是这样用的呢。

没有问题?

Eclipse 工具有这样的警告提示 警告:

Paste_Image.png

This Handler class should be static or leaks might occur (com.example.ta.HandlerActivity.1)
意思:class 应该使用静态声明否则可能出现内存泄露。

为啥出现这样的问题呢

Handler 的生命周期与Activity 不一致

handler 引用 Activity 阻止了GC对Acivity的回收

如何避免

修改代码如下:

public class HandlerActivity2 extends Activity {  
  
    private static final int MESSAGE_1 = 1;  
    private static final int MESSAGE_2 = 2;  
    private static final int MESSAGE_3 = 3;  
    private final Handler mHandler = new MyHandler(this);  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 60000);  
  
        // just finish this activity  
        finish();  
    }  
  
    public void todo() {  
    };  
  
    private static class MyHandler extends Handler {  
        private final WeakReference<HandlerActivity2> mActivity;  
  
        public MyHandler(HandlerActivity2 activity) {  
            mActivity = new WeakReference<HandlerActivity2>(activity);  
        }  
  
        @Override  
        public void handleMessage(Message msg) {  
            System.out.println(msg);  
            if (mActivity.get() == null) {  
                return;  
            }  
            mActivity.get().todo();  
        }  
    }  

上面这样就可以了吗?

当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?
正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?
解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。

代码如下:

 @Override  
 public void onDestroy() {  
     mHandler.removeMessages(MESSAGE_1);  
     mHandler.removeMessages(MESSAGE_2);  
     mHandler.removeMessages(MESSAGE_3);  
  
     // ... ...  
  
     mHandler.removeCallbacks(mRunnable);  
  
     // ... ...  
 }     

如果上面觉的麻烦,也可以如下面:

@Override  
public void onDestroy() {  
    //  If null, all callbacks and messages will be removed.  
    mHandler.removeCallbacksAndMessages(null);  
} 
上一篇下一篇

猜你喜欢

热点阅读