Android實戰技巧之三十八:Handler使用中可能引發的記憶體流失

來源:互聯網
上載者:User

標籤:訊息   有一個   switch   looper   一段   function   有關   tco   run   

問題描寫敘述

曾幾何時,我們用原來的辦法使用Handler時會有以下一段溫馨的提示:

This Handler class should be static or leaks might occur

以下是更具體的說明(Android Studio上的警告,不知道Eclipse上是否同樣)

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

大概意思就是:

一旦Handler被聲明為內部類,那麼可能導致它的外部類不可以被記憶體回收。假設Handler是在其它線程(我們通常成為worker thread)使用Looper或MessageQueue(訊息佇列)。而不是main線程(UI線程),那麼就沒有這個問題。

假設Handler使用Looper或MessageQueue在主線程(main thread),你須要對Handler的聲明做例如以下改動:
聲明Handler為static類。在外部類中執行個體化一個外部類的WeakReference(弱引用)而且在Handler初始化時傳入這個對象給你的Handler;將全部引用的外部類成員使用WeakReference對象。

解決方式一

上面的描寫敘述中基本上把推薦的改動方法明白表達了出來。以下的代碼是我自己使用中的一個實現,請參考:

private CopyFileHandler mHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_appstart);    mHandler = new CopyFileHandler(this);    startCopyDBThread();}private void startCopyFileThread(){    Log.d(TAG, "startCopyDBThread");    new Thread(new Runnable() {        @Override        public void run() {            //DO SOMETHING LIKE: copyDBFile();            Message msg=mHandler.obtainMessage();            mHandler.sendMessage(msg);        }    }).start();}private static class CopyFileHandler extends Handler {    WeakReference<AppStartActivity> mActivity;    public CopyFileHandler(AppStartActivity activity) {        mActivity = new WeakReference<>(activity);    }    public void handleMessage(Message msg) {        final AppStartActivity activity = mActivity.get();       //handle you message here!    }}
為什麼會記憶體流失

那麼為什麼不這樣做會引發記憶體流失呢?
這與幾個關鍵詞有關:內部類、Handler的訊息迴圈(Looper)、Java記憶體回收機制。
須要強調一下,並非每次使用Handler都會引發記憶體流失。這裡面有一定的幾率,須要滿足特定條件才會引起泄漏。


內部類會有一個指向外部類的引用。
記憶體回收機制中約定。當記憶體中的一個對象的引用計數為0時。將會被回收。
Handler作為Android上的非同步訊息處理機制(好吧,我大多用來進行worker thread與UI線程同步),它的工作是須要Looper和MessageQueue配合的。簡單的說,要維護一個迴圈體(Looper)處理訊息佇列(MessageQueue)。

每迴圈一次就從MessageQueue中取出一個Message。然後回調對應的訊息處理函數。

假設,我是說假設,迴圈體中有訊息未處理(Message排隊中),那麼Handler會一直存在。那麼Handler的外部類(一般是Activity)的引用計數一直不會是0,所以那個外部類就不能被記憶體回收。

非常多人會遇到activity的onDestroy方法一直不運行就是這個原因。

還有一個解決方式的嘗試

警告描寫敘述中提到了Handler在worker thread中使用Looper或MessageQueue,我嘗試了一下。請大家品鑒。

    private Handler testHandler;    private Thread mThread = new Thread() {        public void run() {            Log.d(TAG,"mThread run");            Looper.prepare();            testHandler = new Handler() {                public void handleMessage(Message msg) {                    Log.d("TAG", "worker thread:"+Thread.currentThread().getName());                    switch (msg.what) {                        //handle message here                    }                }            };            Looper.loop();        }    };    //start thread here    if(Thread.State.NEW == mThread.getState()) {        Log.d(TAG, "mThread name: " + mThread.getName());        mThread.start();    }    //send message here    testHandler.sendEmptyMessage(1);

參考:
http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler
http://m.blog.csdn.net/blog/wurensen/41907663
http://blog.csdn.net/lmj623565791/article/details/38377229

Android實戰技巧之三十八:Handler使用中可能引發的記憶體流失

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.