1. 咱們爲何須要Android的消息機制java
咱們知道,Android規定訪問UI只能在主線程中進行。若在子線程中訪問UI,就會拋出異常。這個驗證由ViewRootImpl的checkThread方法來完成。安全
爲何不容許在非主線程訪問UI呢,這是由於Android的UI控件不是線程安全的。併發訪問會致使控件處於不可預期的狀態。數據結構
那爲何不對UI訪問加上鎖機制呢,緣由以下:併發
(1)這顯然會讓UI訪問的邏輯變得極其複雜;ide
(2)除了效率問題,鎖機制還會阻塞某些進程的執行。oop
可是Android又不建議在主線程進行耗時操做,由於這可能會引發ANR。所以,便出現了Android的消息機制。post
本文原創,轉載請註明出處:http://blog.csdn.net/seu_calvin/article/details/52120086ui
2. Android的消息機制結構this
Android的消息機制主要是指Handler的運行機制。Handler的運行須要底層MessageQueue和Looper的支撐。spa
2.1 MessageQueue
MessageQueue採用單鏈表的數據結構存儲消息列表。對外提供插入(enqueueMessage)和讀取(next)工做。讀取自己附帶刪除操做。單鏈表在插入和刪除上比較有優點。
enqueueMessage方法根據消息的延遲時間來進行的單鏈表的插入操做,next方法是一個無限循環,若是消息隊列中沒有消息,就會阻塞,當有新消息到來時,next方法就返回這條消息並將其從單鏈表中刪除。
2.2 Looper
Looper以無限循環的形式去消息隊列查找是否有新消息,若是有,就處理消息,不然就一直阻塞等待。
須要注意的是,Handler在建立時會採用當前線程的Looper來構造消息循環系統,Handler內部是經過ThreadLocal來實現的。
有一種狀況是HandlerThread,HandlerThread 繼承自Thread,內部已經封裝了Looper。並對外提供本身這個Looper對象的get方法,這就是它和普通Thread惟一不一樣的地方。具體關於HandlerThread的使用以及特性介紹請查看Android開發——HandlerThread以及IntentService詳解。
ThreadLocal適用於某些數據以線程爲做用域而且不一樣線程具備不一樣數據副本的場景。
ThreadLocal能夠在不一樣線程中互不干擾地存儲並提供數據,經過它能夠獲取每一個線程的Looper。
ThreadLocal的神奇功能介紹請看以前寫過的一篇博文,Android開發——ThreadLocal功能介紹。
(1)UI線程,即ActivityThread被建立時會初始化Looper,所以在主線程默承認以使用Handler。
(2)子線程默認是沒有Looper的,Handler建立前,必須手動建立,不然會報錯。經過Looper.prepare()便可爲當前線程建立一個Looper,並經過Looper.loop()來開啓消息循環。以下所示。
new Thread(){ @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }.start();
Looper的loop()方法極其重要。由於它消息循環系統才真正起做用。
loop方法就是一個死循環,跳出死循環的惟一條件是MessageQueue的next返回了null。當Looper的quit方法被調用時,MessageQueue的next就會返回了null。
loop方法會調用MessageQueue的next方法,next是一個阻塞操做,前面也講過了。只有當next返回了新消息,Looper纔會處理這條消息。這樣Handler發送的消息最終又交給它的dispatchMessage方法來處理。可是Handler的dispatchMessage方法是在建立Handler時所使用的Looper中執行的。這樣就將邏輯切換到指定線程中去執行了。
Looper也是能夠退出的,Looper提供quit和quitSafely來退出一個Looper。惟一的區別是,後者會處理完消息隊列中已有的消息後才安全退出,前者直接退出。Looper退出後,經過Handler發送消息會失敗,send方法返回false。在子線程中,手動建立的Looper在不須要時應quit退出,不然會此線程會一直處於等待狀態。
2.3 Handler
Handler主要工做是消息的發送和接收。
消息的發送能夠使用Handler的post的方法(最終仍是經過send方法完成)將一個Runnable投遞到Looper中去處理,send方法發送一個消息也是同理。
這裏咱們有必要對這兩種方式進行說明。
handler.post(new Runnable(){ @Override public void run() { //do something }});
或者這種用法的變形,用途很廣,功能是延遲3秒後從歡迎界面進入主界面。這裏並非開啓了一個新的線程。
new Handler().postDelayed(new Runnable() { @Override public void run() { Intent intent = new Intent(SplashActivity.this, MainActivity.class); startActivity(intent); finish(); } }, 3000);
post方法的使用如上所示,咱們還知道Hanlder中也有一個handler.sendMessage(Messagemsg)方法,這兩個方法有什麼區別呢?
看一下handler.post(Runnable callback)方法的源碼,很明顯最終仍是經過send方法完成的。
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
再看一下sendMessageDelayed的源碼:
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
這裏面有個關鍵就是方法getPostMessage(r)這個方法,他將Runnable轉成一個Message,他內部到底幹了什麼呢?看一下他的源碼:
private final Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
這裏面就是將Runnable轉化成一個Message,其餘看他的代碼很簡單,就是先獲取一個空消息Message.obtain(),而後將Message中私有變量callback的值設置成Runnable。
send方法被調用時,會調用MQ的enqueueMessage方法將這個消息放入消息隊列中,MQ的next方法會返回這條消息給Looper,Looper發現新消息到來會處理之,最終消息交給Handler處理。dispatchMessage方法被調用,過程以下。
public void dispatchMessage(Message msg){ if(msg.callback!=null){ handleCallback(msg); }else{ if(mCallback!=null){ if(mCallback.handleMessge(msg)){ return; } } handleMessage(msg); } }
首先檢查Message的callback不爲null,不爲null就意味着,callback是一個Runnable對象(實際上就是Handler的post方法所傳遞的Runnable參數),這就是從post方法來實現的。就經過handleCallback來處理消息。handleCallback邏輯很簡單,直接就是msg.callback.run(),執行咱們在Runnable方法裏重寫的run方法。
其次檢查mCallback不爲空,調用mCallback的handleMessage方法來處理消息。
這是爲了處理如下這種Handler的使用狀況。CallBack能夠用來建立一個Handler的實例但並不須要派生Handler的子類。
Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return false; } });
若咱們直接返回了true,就不用再處理消息了。返回false,或者mCallback爲空,會在最後執行Handler的handleMessage(msg)方法來處理消息。
這樣咱們就分析完了Android消息機制的整個流程。