Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> Android Handler 避免內存洩漏的用法總結

Android Handler 避免內存洩漏的用法總結

編輯:Android編程入門

  Android開發經常會用到handler,但是我們發現每次使用Handler都會出現:This Handler class should be static or leaks might occur(null)這樣的提示。Android lint就是為了提示我們,這樣使用Handler會容易造成內存洩漏。但是你會發現其實改成static並沒有什麼用。因為這並沒有解決這個問題的根本。

  首先,我們得確認,為什麼會有內存洩漏?因為Handler是基於消息的。每次new 出Handler,都會創建一個消息隊列用於處理你使用handler發送的消息,形如:handler.send***Message。由於消息的發送總是會有先來後到的區別(如果只是這樣都還好,畢竟再慢也不會太久,總歸可以跑完,可能會延遲個幾秒),但是如果你使用的是sendMessageDelayed(Message msg, long delayMillis)或postDelayed(Runnable r, long delayMillis)等發送延遲消息的時候,那基本內存洩漏發生的概率已經在90%以上了。

  我舉個通常的例子,就是我們在Activity中使用handler來更新UI控件,這是比較常見的。

public class DemoActivity extends Activity {

    private Handler mHandler; 

    protected void onCreate(Bundle savedInstanceState) {
        mHandler = new Handler();
     mHandler.postDelayed(new Runnable() {
       Log.i("wytings","-----------postDelayed-------"); view.setVisibility(View.GONE); }, 50000);
        ...
    }
  ... }

  如果我們瘋狂的對這個Activity進行橫屏和豎屏切換的話,那麼Activity就會不斷的被銷毀和重建。理論上被關閉的Activity應該會再特定時候被回收,也就是我們的內存會在一定的范圍內上下起伏,但是實際上,會發現消耗的內存會隨著切換橫屏的次數一直慢慢增加。這其實已經說明我們的內存洩漏了,如果你會查看內存,你會發現裡面有成堆的DemoActivity實例沒辦法回收。

  這是因為view中使用的Context就是當前的Activity,而這個runnable一旦被post,就會一直存在於隊列裡面,直到時間到了,被執行。意思是這個時間段內Activity即使已經被destroy了但是這個對象還是沒辦法回收,你會發現50秒好,會有一堆"-----------postDelayed-------"的log打印出來,雖然你已經被這個應用關閉了並且你以為即使打印也應該只打印一次……

  那怎麼樣才可以避免這中問題呢,如果你網上一搜你會看到很多關於弱引用的文章。這確實是一個解決的辦法。其原理就是讓所有在handler裡面使用的對象都變成弱引用,目的就是為了可以在Android回收內存的時候,可以直接回收掉。我真覺得如果只是寫這種辦法的人,絕對是屬於拷貝黨,因為這完全是就事論事。你想想就明白,我們寫這個Handler是因為我們要使用它。怎麼可以通過這種弱引用的辦法去處理這類問題呢?讓JVM想回收就回收?!如果這樣,那我們還需要在使用Bitmap的時候,recycle()干嘛,還不如直接弄成軟引用得了。

  這裡需要再插播一下關於Java裡面引用的知識:

Java引用的知識 強引用(Strong Reference) 默認引用。如果一個對象具有強引用,垃圾回收器絕不會回收它。在內存空 間不足時,Java虛擬機寧願拋出OutOfMemory的錯誤,使程序異常終止,也不會強引用的對象來解決內存不足問題。 軟引用(SoftReference) 如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。 弱引用(WeakReference) 在垃圾回收器一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。 虛引用(PhantomReference) 如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。

  如果你運氣好,你會碰到一些除了寫弱引用這個方法後,還有一個就是handler.removeCallbacksAndMessages(null);,就是移除所有的消息和回調,簡單一句話就是清空了消息隊列。注意,不要以為你post的是個Runnable或者只是sendEmptyMessage。你可以看一下源碼,在handler裡面都是會把這些轉成正統的Message,放入消息隊列裡面,所以清空隊列就意味著這個Handler直接被打成原型了,當然也就可以回收了。

  所以,我覺得最好的辦法就是你在使用Handler的時候,在外面的Activity或者Fragment中的關閉方法中,如onDestroy中調用一下handler.removeCallbacksAndMessages(null);就可以了,不應該改成軟引用。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved