在Android異步消息處理中,
Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // } };
但當我們這麼寫時,編譯器會給出警告提示:Handler類應該是靜態的,可能發生內存泄漏。
原因:
在Java中,非靜態的內部類和匿名內部類都會隱式地持有其外部類的引用。靜態的內部類不會持有外部類的引用。
這裏Handler是一個匿名內部類的實例,其持有外面的Activity的引用,所以當Handler伴隨一個耗時後臺線程時就會出現Activity無法回收,進而內存泄露。
解決方法:
一:將Handler聲明爲靜態內部類。
因爲靜態的內部類不會持有外部類的引用,所以不會導致外部類實例的內存泄露。由於Handler不再持有外部類對象的引用了,導致程序不允許你在Handler中操作Activity中的對象。所以如果要在靜態內部類中調用外部的Activity時,我們使用弱引用來處理(WeakReference)。
private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } }
二:postDelayed(new Runnable(),10000)情況
mHandler.postDelayed(new Runnable() { @Override public void run() { // } }, 10000);
在handler的post方法中我們加入了一個匿名的runnable,同時我將其執行延遲了10秒。
被延遲的消息會在被處理之前一直存在於主線程消息隊列中。同時new Runnable也是匿名內部類實現的,同樣也會持有Activity的引用。
這時候我們還需要將Runnable設置爲靜態的成員屬性。
private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } };
同時onCreate()中mHandler.postDelayed(sRunnable, 10000);
另一個方法是使用Handler的removeCallbacksAndMessages ()方法,把消息對象從消息隊列移除。
當參數爲null的時候,可以清除掉所有跟次handler相關的Runnable和Message,我們在onDestroy中調用次方法清理掉所有Messages。
protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); };
總結:
當我們使用非靜態內部類時,如果其實例的持有對象的生命週期大於其外部類對象,那麼就有可能導致內存泄露。方案:
使用靜態的內部類; 對所有handler/Runnable中的變量都用弱引用。關於引用:
? 強引用:如“Object obj = new Object()”,這類引用是Java程序中最普遍的。只要強引用還存在,垃圾收集器就永遠不會回收掉被引用的對象。 ? 軟引用:它用來描述一些可能還有用,但並非必須的對象。在系統內存不夠用時,這類引用關聯的對象將被垃圾收集器回收。JDK1.2之後提供了SoftReference類來實現軟引用。 ? 弱引用:它也是用來描述非需對象的,但它的強度比軟引用更弱些,被弱引用關聯的對象只能生存島下一次垃圾收集發生之前。當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。在JDK1.2之後,提供了WeakReference類來實現弱引用。 ? 虛引用:最弱的一種引用關係,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。爲一個對象設置虛引用關聯的唯一目的是希望能在這個對象被收集器回收時收到一個系統通知。JDK1.2之後提供了PhantomReference類來實現虛引用。
參考
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html