#經過源碼分析Android 的消息處理機制java
咱們知道,Android應用是經過消息來驅動的,每個進程被fork以後,都會在該進程的UI線程(主線程)中啓動一個消息隊列,主線程會開啓一個死循環來輪訓這個隊列,處理裏面的消息。數據結構
經過Android進程的入口 ActivityThread#main 方法能夠看到這個邏輯:oop
public static void main(String[] args) { Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); Looper.loop(); //只要運行正常,都不會執行到這段代碼 throw new RuntimeException("Main thread loop unexpectedly exited"); }
另外,咱們在平時開發中,若是想在子線程中更新UI,必須手動建立一個Looper對象,而且調用它的loop方法:源碼分析
class TestThread extends Thread { public Handler mHandler; public void run() { // 爲當前線程建立Looper對象,同時消息隊列MessageQueue也準備好了 Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { //這裏能夠更新UI了 } }; // 開始處理消息隊列中的消息 Looper.loop(); } }
在這兩個過程當中,都看到了Looper的身影,由於Looper就是消息隊列的管理者,咱們調用他的prepareMainLooper和prepare方法,就會爲當前線程建立好消息隊列,調用looper方法就會開始消息隊列的輪詢處理過程。ui
要理解消息處理機制,除了Looper,咱們還要理解其餘類:this
- MessageQueue:消息隊列
- Message:消息
- Handler:消息的處理者
先從Looper開始,上面提到的兩個靜態方法 prepareMainLooper()和prepare()的做用就是爲當前線程建立消息隊列,loop()調度這個消息隊列。spa
來看Looper#prepareMainLooper:線程
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
prepareMainLooper是經過調用prepare()方法實現,而且經過myLooper()方法獲得了當前線程的Looper,主線程的Looper,就是sMainLooper。code
接着看prepare方法:對象
/** * @param uitAllowed 是否容許消息循環退出,在ActivityThread#main 中,咱們建立的是主線程的消息循環,確定不容許退出,其餘地方,則能夠退出 */ private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
這個方法中爲每個線程new了一個Looper對象,而且設置到sThreadLocal中。sThreadLocal是ThreadLocal類型的變量(線程局部變量),它保證了每個線程有一個本身獨有的Looper對象,
myLooper():
/** * 從sThreadLocal中獲取當前線程的Looper對象 */ public static Looper myLooper() { return sThreadLocal.get(); }
方法很簡單,就是返回了當前線程所獨有的那個Looper對象。
Looer對象建立好了,同時消息隊列也建立好了,接下來就是讓整個消息機制跑起來,這就須要經過Looper#loop實現:
public static void loop() { //獲得當前線程的Looper final Looper me = myLooper(); //沒有Looper對象,直接拋異常 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //獲得當前Looper對應的消息隊列 final MessageQueue queue = me.mQueue; //一個死循環,不停的處理消息隊列中的消息,消息的獲取是經過MessageQueue的next()方法實現 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } //調用Message的target變量(也就是Handler了)的dispatchMessage方法來處理消息 msg.target.dispatchMessage(msg); msg.recycleUnchecked(); } }
首先,獲得當前線程的Looper,再經過Looper獲得當前線程的消息循環,而後輪詢這個消息隊列,處理每個消息,下面我就來看消息隊列MessageQueue以及消息Message。
MessageQueue就是Message隊列,消息隊列這一數據結構是經過一個Message鏈實現的,Message對象有一個next字段指向它的下一結點。
public final class MessageQueue { Message mMessages; //消息隊列的初始化,銷燬,輪詢過程,阻塞,喚醒,都是經過本地方法實現的 private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native static void nativePollOnce(long ptr, int timeoutMillis); private native static void nativeWake(long ptr); private native static boolean nativeIsIdling(long ptr); /** * 把消息加入到消息循環中 * @param msg * @param when 是麼時候被執行,在消息隊列中會按照時間排序 */ boolean enqueueMessage(Message msg, long when) {} /** * 把消息加入到消息循環中 * @param msg * @param when 何時被執行 */ boolean enqueueMessage(Message msg, long when) {} /**移除消息*/ void removeMessages(Handler h, int what, Object object) { }
Message對象放入隊列經過enqueueMessage()方法實現,消息的依次獲取是經過next()方法實現,其中當獲取不到可處理Message對象時,該方法會進入等待狀態。
Message就是消息的封裝對象,它實現了Parcelable接口,所以能夠跨進程傳輸。
public final class Message implements Parcelable { //消息的標識符 public int what; //兩個int形的擴展參數 public int arg1; public int arg2; //一個Object拓展參數 public Object obj; //消息發送者的UID public int sendingUid = -1; //消息帶的data Bundle data; //target對象,也就是處理當前消息的Handler Handler target; //指向消息隊列中下一個消息 Message next; //消息同步鎖 private static final Object sPoolSync = new Object(); //消息池 private static Message sPool; //消息池大小 private static int sPoolSize = 0; //消息池最大消息數量 private static final int MAX_POOL_SIZE = 50; }
對消息的管理是經過一個消息池來實現的,由於消息池的存在,咱們在須要建立一個Message對象時,最好使用可複用消息對象的方法來建立它。
正確的使用方法是:
Message msg = mHandler.obtainMessage(WHAT); msg.sendToTarget();
obtainMessage方法中實際上會調用Message#obtain方法來從消息池中取一個對象。
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
錯誤的使用方法:
Message msg = new Message(); msg.what = WHAT; mHandler.sendMessage(msg);
Handler 就是消息循環(MessageQueue)中消息(Message)的真正處理者,經過Looper#loop能夠看到:
public static void loop() { for (;;) { Message msg = queue.next(); // might block msg.target.dispatchMessage(msg); } }
Message的target屬性就是一個Handler對象,對消息的處理其實是經過Handler#dispatchMessage方法來處理的,而dispatchMessag方法會調用Handler#handleMessage方法,咱們能夠重寫handleMessage方法 來真正的處理消息的回調。