1. 程式人生 > 實用技巧 >Handler和它的朋友們(流程、記憶體洩露相關)

Handler和它的朋友們(流程、記憶體洩露相關)

>>> hot3.png

流程:

1.Looper.prepare()

為當前執行緒set一個Looper(通過ThreadLocal.set方法)

新建立的Looper裡面有一個MessageQueue的成員變數

173516_rWpX_1029054.png

220923_H4tC_1029054.png

2.Handler handler = new Handler();

handler得到一個當前執行緒的Looper物件(通過ThreadLocal.get方法),從而得到Looper的MessageQueue物件

173537_86MP_1029054.png

173541_nmWM_1029054.png

Looper:

173547_F5oI_1029054.png

173524_bHOn_1029054.png

3.Looper.loop()

死迴圈將MessageQueue裡面的Message物件交給handler處理

//因為這個方法裡面有個死迴圈,Looper.loop()後面的程式碼不能被執行。

173554_Daw3_1029054.png

173610_MafP_1029054.png

173615_tqVy_1029054.png

msg.target.dispatchMessage(msg); //此方法就是將message分配到Handler處理

4.handler.sendMessage

將這個Message進行入隊操作(通過建立Handler時得到MessageQueue物件)

173621_IP40_1029054.png

173625_NccW_1029054.png

記憶體洩露

This Handler class should be static or leaks might occur問題

如果在一個Activity或者其他類中定義了一個Handler的非靜態內部類,AndroidStudio會出現以下提示:

173632_NPSW_1029054.png

原因:

1.非靜態的內部類持有其外部類的引用,所以這裡的Handler內部類持有Activity的引用。

2.從上面第四步可以看出:handler.sendMessage方法會呼叫enqueueMessage,enqueueMessage方法會讓傳送的message物件持有當前的Handler的引用(看標註1)。

引用鏈如下圖

173637_TvEv_1029054.png

3.如果Activity呼叫finish時,Handler的MessageQueue中還有未處理的Message,這個Message持有Handler的引用,Handler持有Activity的引用,這樣會使得Activity不能被回收,而引起記憶體洩露,直到所有的MessageQueue中的Message處理完畢(Message的recycleUnchecked方法會使target置空(看標註2),Message不再持有Handler的引用)。

另外如果呼叫的是sendMessageDelayed,那麼在delay到達前,message也會一直持有handler的引用,此時Activity呼叫finish,Activity也是不能被回收。

還有一種情況就是,耗時任務的執行緒(下載圖片)持有handler的引用(sendMessage通知主執行緒進度),Activity呼叫finish時,耗時任務執行緒沒執行完畢,Activity也不能被回收。

173642_GaPw_1029054.png

解決辦法:

1.將Handler改為靜態內部類,構造方法傳進Activity,並定義為弱引用

2.在Activity onDestory方法呼叫

handler.removeCallbacksAndMessages(null);

但這種只能解決Message引用Handler,Handler引用Activity這種情況。

轉載於:https://my.oschina.net/stphwn/blog/1813694