Android App 記憶體泄露之Handler

來源:互聯網
上載者:User

Android App 記憶體泄露之Handler
Android App 記憶體泄露之Handler

Handler也是造成記憶體泄露的一個重要的源頭,主要Handler屬於TLS(Thread Local Storage)變數,生命週期和Activity是不一致的,Handler引用Activity會存在記憶體泄露。
看一下如下代碼
/** *  * 實現的主要功能。 * @version 1.0.0  * @author Abay Zhuang 
* Create at 2014-7-28 */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 工具有這樣的警告提示 警告:

This Handler class should be static or leaks might occur (com.example.ta.HandlerActivity.1)意思:class 使用靜態聲明否者可能出現記憶體泄露。
為啥出現這樣的問題呢Handler 的生命週期與Activity 不一致
  • 當Android應用啟動的時候,會先建立一個UI主線程的Looper對象,Looper實現了一個簡單的訊息佇列,一個一個的處理裡面的Message對象。主線程Looper對象在整個應用生命週期中存在。
  • 當在主線程中初始化Handler時,該Handler和Looper的訊息佇列關聯(沒有關聯會報錯的)。發送到訊息佇列的Message會引用發送該訊息的Handler對象,這樣系統可以調用 Handler#handleMessage(Message) 來分發處理該訊息。handler 引用 Activity 阻止了GC對Acivity的回收
    • 在Java中,非靜態(匿名)內部類會預設隱性引用外部類對象。而靜態內部類不會引用外部類對象。
    • 如果外部類是Activity,則會引起Activity泄露 。

      當Activity finish後,延時訊息會繼續存在主線程訊息佇列中1分鐘,然後處理訊息。而該訊息引用了Activity的Handler對象,然後這個Handler又引用了這個Activity。這些引用對象會保持到該訊息被處理完,這樣就導致該Activity對象無法被回收,從而導致了上面說的 Activity泄露。

      如何避免修?
      • 使用顯形的引用,1.靜態內部類。 2. 外部類
      • 使用弱引用 2. WeakReference修改代碼如下:
        /** *  * 實現的主要功能。 *  * @version 1.0.0 * @author Abay Zhuang 
        * Create at 2014-7-28 */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 mActivity; public MyHandler(HandlerActivity2 activity) { mActivity = new WeakReference(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)等。

        代碼如下:

         
           /**     * 一切都是為了不要讓mHandler拖泥帶水     */    @Override    public void onDestroy() {        mHandler.removeMessages(MESSAGE_1);        mHandler.removeMessages(MESSAGE_2);        mHandler.removeMessages(MESSAGE_3);        // ... ...        mHandler.removeCallbacks(mRunnable);        // ... ...    }   

        如果上面覺的麻煩,也可以如下面:

        @Overridepublic void onDestroy() {    //  If null, all callbacks and messages will be removed.    mHandler.removeCallbacksAndMessages(null);}

        敬請期待下一章(^__^) 嘻嘻……

        也可以關注我的github


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.