Android開發常常會用到handler,可是咱們發現每次使用Handler都會出現:This Handler class should be static or leaks might occur(null)這樣的提示。Android lint就是爲了提示咱們,這樣使用Handler會容易形成內存泄漏。可是你會發現其實改爲static並無什麼用。由於這並無解決這個問題的根本。html
首先,咱們得確認,爲何會有內存泄漏?由於Handler是基於消息的。每次new 出Handler,都會建立一個消息隊列用於處理你使用handler發送的消息,形如:handler.send***Message。因爲消息的發送老是會有先來後到的區別(若是隻是這樣都還好,畢竟再慢也不會過久,總歸能夠跑完,可能會延遲個幾秒),可是若是你使用的是sendMessageDelayed(Message msg, long delayMillis)或postDelayed(Runnable r, long delayMillis)等發送延遲消息的時候,那基本內存泄漏發生的機率已經在90%以上了。post
我舉個一般的例子,就是咱們在Activity中使用handler來更新UI控件,這是比較常見的。spa
1 public class DemoActivity extends Activity { 2 3 private Handler mHandler; 4 5 protected void onCreate(Bundle savedInstanceState) { 6 mHandler = new Handler(); 7 8 mHandler.postDelayed(new Runnable() { 9 Log.i("wytings","-----------postDelayed-------"); 10 view.setVisibility(View.GONE); 11 }, 50000); 12 ... 13 } 14
若是咱們瘋狂的對這個Activity進行橫屏和豎屏切換的話,那麼Activity就會不斷的被銷燬和重建。理論上被關閉的Activity應該會再特定時候被回收,也就是咱們的內存會在必定的範圍內上下起伏,可是實際上,會發現消耗的內存會隨着切換橫屏的次數一直慢慢增長。這其實已經說明咱們的內存泄漏了,若是你會查看內存,你會發現裏面有成堆的DemoActivity實例沒辦法回收。code
這是由於view中使用的Context就是當前的Activity,而這個runnable一旦被post,就會一直存在於隊列裏面,直到時間到了,被執行。意思是這個時間段內Activity即便已經被destroy了可是這個對象仍是沒辦法回收,你會發現50秒好,會有一堆"-----------postDelayed-------"的log打印出來,雖然你已經被這個應用關閉了而且你覺得即便打印也應該只打印一次……htm
那怎麼樣才能夠避免這中問題呢,若是你網上一搜你會看到不少關於弱引用的文章。這確實是一個解決的辦法。其原理就是讓全部在handler裏面使用的對象都變成弱引用,目的就是爲了能夠在Android回收內存的時候,能夠直接回收掉。我真以爲若是隻是寫這種辦法的人,絕對是屬於拷貝黨,由於這徹底是就事論事。你想一想就明白,咱們寫這個Handler是由於咱們要使用它。怎麼能夠經過這種弱引用的辦法去處理這類問題呢?讓JVM想回收就回收?!若是這樣,那咱們還須要在使用Bitmap的時候,recycle()幹嗎,還不如直接弄成軟引用得了。對象
這裏須要再插播一下關於Java裏面引用的知識:blog
強引用(Strong Reference) | 默認引用。若是一個對象具備強引用,垃圾回收器毫不會回收它。在內存空 間不足時,Java虛擬機寧願拋出OutOfMemory的錯誤,使程序異常終止,也不會強引用的對象來解決內存不足問題。 |
軟引用(SoftReference) | 若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。 |
弱引用(WeakReference) | 在垃圾回收器一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。 |
虛引用(PhantomReference) | 若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。 |
若是你運氣好,你會碰到一些除了寫弱引用這個方法後,還有一個就是handler.removeCallbacksAndMessages(null);,就是移除全部的消息和回調,簡單一句話就是清空了消息隊列。注意,不要覺得你post的是個Runnable或者只是sendEmptyMessage。你能夠看一下源碼,在handler裏面都是會把這些轉成正統的Message,放入消息隊列裏面,因此清空隊列就意味着這個Handler直接被打成原型了,固然也就能夠回收了。隊列
因此,我以爲最好的辦法就是你在使用Handler的時候,在外面的Activity或者Fragment中的關閉方法中,如onDestroy中調用一下handler.removeCallbacksAndMessages(null);就能夠了,不該該改爲軟引用。內存
轉自:http://www.cnblogs.com/wytings/p/5225278.html開發