天天看點

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記憶體洩露分析