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... } } } }如此大功告成!!