基本元素
Handler
用於處理消息,包括將發送消息到消息隊列,和從消息隊列中分發出去。
Message
用戶對屏幕操作而產生的信息。
Looper
一個死循環,不停地輪詢等待線程給它的消息。
MessageQueue
存放消息的隊列,是一個優先級隊列,當新插入一個消息的時候,會先和隊列內的消息的執行時間做對比,然後插入,執行時間越短,優先級越高,具體方法在enqueueMeassage()方法中。
工作流程
首先可以把整個過程當成一個生產流水線,handler是機器手,message就是產品,messagequeue就是流水線的傳輸帶,handler將message發送到傳輸帶messagequeue上,message按照時間順序排列在運輸袋子上,looper就是發動機帶動轉軸,把message運輸出去,最後又是handler把message分發出去。
具體的方法過程如下:
Handler首先調用sendMessage(),而sendMessage又調用MessageQueue的enqueueMessage()方法,該方法的目的是把message存在消息隊列中。
現在消息已經在消息隊列中了,需要一個動力去讓這些消息被挨個的處理,於是我們就需要looper中的loop函數,它會調用queue.next()方法,這就取到了一個隊列中的message,然後handler繼續調用dispatchMessage()方法,該方法就包含了handler的handleMessage()方法,然後就會循環該過程。
常見問題
1.Looper如何停下來
當消息隊列是空的時候,loop執行queue.next()的時候會阻塞,此時就可以停下來。
2.一個線程中幾個handler
隨便多少個,new一個有一個。
3.一個線程有幾個looper
一個,由threadlocal決定。一個線程裏面有一個threadlocalMap類型的變量,裏面保存的是threadlocal,所以threadlocal是個key,value鍵值對,Looper的構造函數是個私有函數,只有在prepare()方法中初始化,在該方法中,set方法會獲取當前線程,獲取當前threadlocalMap,一個線程只對應一個map,map中一個key對應一個value,key是threadlocal,value就是Looper,所以一個線程綁定一個looper。
4.Handler爲什麼會內存泄漏,解決方案
Handler持有Activity。因爲handler是個匿名內部類,可以持有外部類對象,所以handler持有activity。內存泄漏和handler的機制有關,message持有handler,handler又持有activity,message又有延遲處理的情況,所以會一直存在消息隊列中,這時候messageQueue又持有activity,只要message不及時處理,activity就不會被回收。解決方案是:activity弱引用。
5.爲什麼在主線程中可以直接new handler
當啓動app的時候,會先啓動Luncher,然後在linux層,會調用zygote去給每個應用建立一個虛擬機,此時會調用activityThread再去使用main方法,裏面就有prepareMainLooper方法,此時可以知道所有組件都是圍繞主線程looper,以消息存在。
6.怎麼在子線程中new一個handler
先Looper.prepare(),在new handler,最後Looper.loop()
7.子消息Looper,沒有消息怎麼辦
消息隊列沒有消息,會調用nativePollOnce方法,這個方法會進去等待狀態,此時會調用linux的epoll函數並傳入-1,epoll函數會將結果傳入linux的消息隊列中,若這個值是-1,則會陷入永久等待狀態,線程掛起。
8. Looper怎麼退出
調用messageQueue.quit方法,這個過程中,首先removeAllmessageLocked(),把所有的消息全部移出去。此時調用了recycleUnchecked()方法,將消息內部變量賦值爲null,然後調用nativeWake(),這個和epoll相反,它喚醒了線程,並返回一個爲null的msg,Loop中for循環就會終止。
9.主線程需要釋放looper嗎
不能,AMS圍繞handler管理,四大組件也是靠主線程的Looper處理操作
10.多個handler往消息隊列放消息怎麼保證線程安全
加鎖,使用synchronized
11.怎麼生成一個message
使用享元設計模式,提前已經存在了一個消息隊列,已經處理完的消息,會被賦值爲null,並且用頭插法存在這個列表中。當使用obtain的時候會從該消息隊列中獲取一個空消息
12.Looper爲何不會讓應用卡死
二者之間,ANR的原因是消息沒有被及時處理,而looper沒有消息時候會進入睡眠狀態釋放線程。