畫圖說明:安全
我在學習和使用handler的時候,對與它相關的源代碼進行的研究,說到handler機制,就要設計到5個類(畫圖),網絡
Handler、MessageQueue、Looper、Thread、還有一個Message;ide
Message是消息,它由MessageQueue統一列隊,由Handler處理。函數
Handler是處理者,他負責發送和處理Message消息。oop
MessageQueue指消息隊列,它用來存放Handler發送過來的隊列,而且按照先入先出的規則執行。學習
Looper的做用就像抽水的水泵,它不斷的從MessageQueue中去抽取Message並執行。this
Thread線程,是消息循環的執行場所。spa
知道了這幾個類就能夠說說消息機制的原理了,在建立Activity以前,當系統啓動的時候,先加載ActivityThread這個類,在這個類的main函數中,調用Looper.prepareMainLooper()進行初始化Looper對象,而後建立主線程的handler對象,隨後才建立ActivityThread對象,最後調用Looper.loop()方法,不斷的進行輪詢消息隊列中的消息。也就是說,在ActivityThread和Activity建立以前,就已經開啓了Looper的loop()方法,不斷的進行輪詢消息。線程
咱們能夠畫圖來講明handler機制的原理:設計
咱們經過Message.obtain()準備消息數據以後,
第一步是使用sendMessage():經過Handler將消息發送給消息隊列
第二步、在發送消息的時候,使用message.target=this爲handler發送的message貼上當前handler的標籤
第三步、開啓HandlerThread線程,執行run方法。
四、在HandlerThread類的run方法中開啓輪詢器進行輪詢:調用Looper.loop()方法進行輪詢消息隊列的消息
五、在消息隊列MessageQueue中enqueueMessage(Message msg, long when)方法裏,對消息進行入列,即依據傳入的時間進行消息入列(排隊)
六、輪詢消息:與此同時,Looper在不斷的輪詢消息隊列
七、在Looper.loop()方法中,獲取到MessageQueue對象後,從中取出消息(Message msg = queue.next()),若是沒有消息會堵塞
八、分發消息:從消息隊列中取出消息後,調用msg.target.dispatchMessage(msg);進行分發消息
九、將處理好的消息分發給指定的handler處理,即調用了handler的dispatchMessage(msg)方法進行分發消息。
十、在建立handler時,複寫的handleMessage方法中進行消息的處理
十一、回收消息:在消息使用完畢後,在Looper.loop()方法中調用msg.recycle(),將消息進行回收,即將消息的全部字段恢復爲初始狀態。
12. what帶字段,obj帶數據, 建立方法 new Message 或 Message.obtain()
handler機制?即handler的做用
在Android的UI開發中,咱們常常會使用Handler來控制主UI程序的界面變化。有關Handler的做用,
咱們總結爲:與其餘線程協同工做,接收其餘線程的消息並經過接收到的消息更新主UI線程的內容。
咱們假設在一個UI界面上面,有一個按鈕,當點擊這個按鈕的時候,會進行網絡鏈接,並把網絡上的一個字符串拿下來顯示到界面上的一個 TextView上面,這時就出現了一個問題,若是這個網絡鏈接的延遲過大,多是10秒鐘甚至更長,那咱們的界面將處於一直假死狀態,而若是這段時間超 過5秒鐘的話,程序會出現異常。
這時咱們會想到使用線程來完成以上工做,即當按鈕被按下的時候新開啓一個線程來完成網絡鏈接工做,並把獲得的結果更新到UI上面。可是,這時候又會 出現另外一個問題,在Android中,主線程是非線程安全的,也就是說UI的更新只能在本線程中完成,其餘線程沒法直接對主線程進行操做。
爲了解決以上問題,Android設計了Handler機制,由Handler來負責與子線程進行通信,從而讓子線程與主線程之間創建起協做的橋樑,使Android的UI更新的問題獲得完美的解決。接下來ATAAW.COM舉例來詮釋Handler的基本使用方法。
A、Handler的工做原理
通常狀況下,在主線程中咱們綁定了Handler,並在事件觸發上面建立新的線程用於完成某些耗時的操做,當子線程中的工做完成以後,會對Handler發送一個完成的信號,而Handler接收到信號後,就進行主UI界面的更新操做。
B、Handler與子線程協做實例
一、建立Handler實現類,在主UI所在類中的內部類
1 class MyHandler extends Handler {
2 public MyHandler() {
1 }
1 public MyHandler(Looper L) {
1 super(L);
1 }
1 // 重寫handleMessage方法,接受數據並更新UI
1 @Override
1 public void handleMessage(Message msg) {
2 super.handleMessage(msg);
1 //此處根據msg內容進行UI操做
1 }
1 }
二、子線程的實現
1 class MyThread implements Runnable {
1 public void run() {
1 Message msg = new Message();
1 Bundle b = new Bundle();
1 b.putString("cmd", "update");
1 msg.setData(b);
1 MainActivity.this.myHandler.sendMessage(msg);//通知Handler更新UI
2 }
1 }
經過以上的兩個實現,咱們只須要在MainActivity中聲明MyHandler實例對象就能夠完成線程之間的通信和界面的更新操做。
MyHandler myHandler = newMyHandler();
調用流程
Message類的obtain方法
把消息池裏的第一條數據取出來,而後把第二條變成第一條
if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; }
建立Handler對象時,在構造方法中會獲取Looper和MessageQueue的對象
public Handler() { ... //拿到looper mLooper = Looper.myLooper(); ... //拿到消息隊列 mQueue = mLooper.mQueue; mCallback = null; }
查看myLooper方法體,發現Looper對象是經過ThreadLocal獲得的,在查找ThreadLocal的set方法時發現
Looper是直接new出來的,而且在Looper的構造方法中,new出了消息隊列對象
sThreadLocal.set(new Looper()); private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }
prepare方法是在prepareMainLooper()方法中調用的
public static final void prepareMainLooper() { prepare(); ... }
在應用啓動時,主線程要被啓動,ActivityThread會被建立,在此類的main方法中
public static final void main(String[] args) { ... //建立Looper和MessageQueue Looper.prepareMainLooper(); ... //輪詢器開始輪詢 Looper.loop(); ... }
Looper.loop()方法中有一個死循環
while (true) { //取出消息隊列的消息,可能會阻塞 Message msg = queue.next(); // might block ... //解析消息,分發消息 msg.target.dispatchMessage(msg); ... }
Linux的一個進程間通訊機制:管道(pipe)。原理:在內存中有一個特殊的文件,這個文件有兩個句柄(引用),一個是讀取句柄,一個是寫入句柄
主線程Looper從消息隊列讀取消息,當讀完全部消息時,進入睡眠,主線程阻塞。子線程往消息隊列發送消息,而且往管道文件寫數據,主線程即被喚醒,從管道文件讀取數據,主線程被喚醒只是爲了讀取消息,當消息讀取完畢,再次睡眠
Handler發送消息,sendMessage的全部重載,實際最終都調用了sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { ... //把消息放到消息隊列中 sent = queue.enqueueMessage(msg, uptimeMillis); ... }
enqueueMessage把消息經過從新排序放入消息隊列
final boolean enqueueMessage(Message msg, long when) { ... final boolean needWake; synchronized (this) { ... //對消息的從新排序,經過判斷消息隊列裏是否有消息以及消息的時間對比 msg.when = when; Message p = mMessages; //把放入消息隊列的消息置爲消息隊列第一條消息 if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; // new head, might need to wake up } else { //判斷時間順序,爲剛放進來的消息尋找合適的位置 Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } //喚醒主線程 if (needWake) { nativeWake(mPtr); } return true; }
Looper.loop方法中,獲取消息,而後分發消息
//獲取消息隊列的消息 Message msg = queue.next(); // might block ... //分發消息,消息由哪一個handler對象建立,則由它分發,並由它的handlerMessage處理 msg.target.dispatchMessage(msg);
message對象的target屬性,用於記錄該消息由哪一個Handler建立,在obtain方法中賦值