android異步消息機制總結與思考
現在在看這幅圖,應該已經很清楚瞭。為什麼可以實現不同線程間的消息傳遞。因為handler發送msg的地方雖然是可以在不同的線程,但是最後發送到的msgQueue都是在該looper綁定的線程裡面。
就拿主線程的mhandler來講,它一定和smainLooper綁定的,smainLooper對應主線程。不管mhandler在哪個thread發送msg(send,post等方式),最後都是放在瞭主線程的msgQueue裡面。
一切的一切都是因為發送消息的地方和處理消息的地方在不同線程,所以實現瞭線程間的通信。那麼再往上想一下,為什麼發消息的地方會不一樣,自然而然的想到瞭handler.sendMessage()的地方;隻要在線程裡這個handler對象拿到瞭,就可以發送消息。
以為到這裡就結束瞭嗎
handler帶來的內存泄漏問題:
先分析下原因
之前提到過,msgQueue裡面拿出msg後可以找到對應的handler去分發處理,是因為msg持有handler的引用。如果hadnler持有是內部類或者匿名類(像handler = new Handler()這樣),那麼handler和外部類(一般是所在的activity)就有聯系,gc工作的時候,就不能把這個activity回收掉。
當然如果msg發送後,馬上就被處理掉,影響也不嚴重。
但是如果是sendMessgaeDelay()延遲瞭10s,那麼至少在這10s內,想要回收這個acitvity是不可能的。就導致瞭內存泄漏。
避免的辦法
根本原因是msg持有handler的引用。handler再持有activity的引用。msg沒處理完,這個activity就不能被GC回收。msg持有handler的引用,這個是不能做修改的,源碼就是那樣設計的。那麼我們能做出改變的就是handler和activity(外部類)的聯系瞭。
內部類不依賴外部類,自然就想到瞭靜態內部類。把handler聲明成static,這樣handler就不依賴activity(外部類)存在瞭,代價就是靜態內部類隻能使用外部類的靜態方法,訪問靜態成員變量。
通用做法靜態類加弱引用
public static class MyHandler extends Handler { WeakReference activity; public MyHandler(WeakReference activity) { this.activity = activity; }
loop循環是否會導致anr的思考:
首先要明確造成anr的原因:應用未響應。指主線程事件得不到處理,或者處理超時(一般是5s)。
Looper.loop();雖然是一個循環,但是它並不會導致事件響應超時。隻是負責取出來分發,具體耗時多少並不是在loop這裡。反而由於它一直在loop,其他事件才得以在主線程分發。