Handler和它的朋友們(流程、記憶體洩露相關)
流程:
1.Looper.prepare()
為當前執行緒set一個Looper(通過ThreadLocal.set方法)
新建立的Looper裡面有一個MessageQueue的成員變數
2.Handler handler = new Handler();
handler得到一個當前執行緒的Looper物件(通過ThreadLocal.get方法),從而得到Looper的MessageQueue物件
Looper:
3.Looper.loop()
死迴圈將MessageQueue裡面的Message物件交給handler處理
//因為這個方法裡面有個死迴圈,Looper.loop()後面的程式碼不能被執行。
msg.target.dispatchMessage(msg); //此方法就是將message分配到Handler處理
4.handler.sendMessage
將這個Message進行入隊操作(通過建立Handler時得到MessageQueue物件)
記憶體洩露
This Handler class should be static or leaks might occur問題
如果在一個Activity或者其他類中定義了一個Handler的非靜態內部類,AndroidStudio會出現以下提示:
原因:
1.非靜態的內部類持有其外部類的引用,所以這裡的Handler內部類持有Activity的引用。
2.從上面第四步可以看出:handler.sendMessage方法會呼叫enqueueMessage,enqueueMessage方法會讓傳送的message物件持有當前的Handler的引用(看標註1)。
引用鏈如下圖
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也不能被回收。
解決辦法:
1.將Handler改為靜態內部類,構造方法傳進Activity,並定義為弱引用
2.在Activity onDestory方法呼叫
handler.removeCallbacksAndMessages(null);
但這種只能解決Message引用Handler,Handler引用Activity這種情況。
轉載於:https://my.oschina.net/stphwn/blog/1813694