天天看点

Android Handler内存泄露分析

   用Lint工具对Android代码进行扫描时,有这样一个关于Handler的警告信息:

This Handler class should be static or leaks might occur。

    这个警告的产生是由于将Handler声明为了非静态内部类(匿名或非匿名),这种情况下可能会产生内存泄露,导致Activity无法释放。

    我们使用Handler post一个Message时,Message会在主线程的MessageQueue中排队。由于消息处理中需要调用Message对应Handler的回调,Message会持有Handler的引用。当Handler为非静态内部类(匿名或非匿名)时,Handler就会持有外部类的引用,如果外部类是Activity,这个Activity对象有可能会泄露,尤其是通过调用Handler的postDelayed()方法发送消息,Message会长时间在MessageQueue中存在,泄露的可能性将更大。

    要解决这个问题,需要做的就是想办法切断这个引用关系链(Message -> Handler -> Activity),要么切断Message -> Handler的引用,要么切断Handler -> Activity的引用。

    针对第一个引用关系,处理方法是在使用Handler的组件生命周期结束前清除掉MessageQueue中的Message对象(比如,在Activity的onDestroy()中调用Handler的remove*方法)。Handler主要有下面一些方法来清楚Message对象:

    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);

    针对第二个引用关系,可以将Handler声明为静态内部类,避免对外部类的强引用,如果在Handler的内部方法中需要引用外部类,可以在其内部声明一个WeakReference引用外部类的实例。

    具体的实现代码如下:

public class MyActivity extends Activity{
    MyHandler myHandler = new MyHandler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandler.removeCallbacksAndMessages(null);
    }

    private static class MyHandler extends Handler{
        private WeakReference<MyActivity> activity;
        MyHandler(MyActivity ac) {
            activity = new WeakReference<MyActivity>(ac);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //do something
            if (activity != null) {
                MyActivity myActivity = activity.get();
                //......
            }
        }
    };
}
           

       欢迎关注我的公众号一起交流学习

Android Handler内存泄露分析