本篇主要介紹Android中的消息機制,即Looper、Handler是如何協同工作的;
Looper:主要用來管理當前線程的消息隊列,每個線程只能有一個Looper
Handler:用來將消息(Message)插入到當前線程的消息隊列,並負責分發Looper中的消息,將消息發送到當前線程執行
具體關系圖如下所示:
接下來我們來分析一下Looper和Handler的源碼,了解一下其中的奧妙。
首先我們從一個程序運行的入口來分析,源碼如下:
public static void main(String[] args){ ...... Looper.prepareMainLooper();//初始化Looper ...... if(smainThreadHandler==null){ smainThreadHandler=thread.getHandler();//初始化Handler } ...... Looper.loop();//消息循環執行 }
可以看出,程序在運行的時候首先會創建主線程的Looper對象,並通過Looper開啟消息循環,不停的取出消息並執行;
接下來我們來研究Looper的源碼;
第一部分:Looper源碼
初始化
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mThread = Thread.currentThread(); 4 } 5 6 初始化Looper對象(該過程包含初始化消息隊列和當前線程對象) 7 private static void prepare(boolean quitAllowed) { 8 if (sThreadLocal.get() != null) { 9 throw new RuntimeException("Only one Looper may be created per thread"); 10 } 11 sThreadLocal.set(new Looper(quitAllowed)); 12 }
可以看出Looper在初始化的時候,首先會創建消息隊列,並通過sThreadLocal保存在當前的線程本地變量中;
再來看一下程序入口Looper.prepareMainLooper();//初始化Looper究竟執行了什么
1 //初始化主線程的Looper對象 2 public static void prepareMainLooper() { 3 prepare(false); 4 synchronized (Looper.class) { 5 if (sMainLooper != null) { 6 throw new IllegalStateException("The main Looper has already been prepared."); 7 } 8 sMainLooper = myLooper(); 9 } 10 }
這里有兩行關鍵的代碼:prepare(false);和sMainLooper = myLooper();
首先我們來看prepare(false);即上面講到的 初始化Looper,可以看看上面的源碼;
我們來看sMainLooper = myLooper();
1 public static @Nullable Looper myLooper() { 2 return sThreadLocal.get(); 3 }
非常簡單,我們上面提到在初始化Looper的時候會把Looper保存到當前線程的本地變量中,而這行代碼的意思
就是從線程本地變量中將looper取出來
有了Looper,程序怎樣才能運行?答案就在Looper.loop();//消息循環執行
1 public static void loop() { 2 final Looper me = myLooper();//得到當前線程的Looper對象 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 5 } 6 final MessageQueue queue = me.mQueue;//得到消息隊列 7 8 ...... 9 10 //執行消息循環 11 for (;;) { 12 Message msg = queue.next(); // might block 13 if (msg == null) { 14 // No message indicates that the message queue is quitting. 15 return; 16 } 17 msg.target.dispatchMessage(msg); 18 msg.recycleUnchecked(); 19 } 20 }
顯而易見,loop方法就是獲取到當前線程的Looper對象,並從中循環取出消息,並執行,程序就這樣跑起來了,具體是如何分發消息的
我們將會在下面講解;
至此我們至少應該明白,當主線程在執行的時候
1、初始化Looper,並將Looper保存的線程變量中
2、Looper在初始化的時候會創建消息隊列,並管理消息隊列
2、取出Looper,並從消息隊列中取出消息,循環執行
第二部分:Handler源碼
我們知道Handler有兩種使用方式,一種是使用handler.post(Runnable r);另一種是復寫handleMessage(Message msg)方法
復寫handleMessage(Message msg)方法非常簡單,Handler在消息分發的時候,直接回調該方法即可,我們主要來研究第一種
1 public final boolean post(Runnable r) 2 { 3 return sendMessageDelayed(getPostMessage(r), 0); 4 }
看到這個我們首先得明白getPostMessage(r)干了什么
1 private static Message getPostMessage(Runnable r) { 2 Message m = Message.obtain(); 3 m.callback = r; 4 return m; 5 }
可以看出是將r封裝成了一個消息,r作為該消息的回調;
我們接着看:
1 public final boolean sendMessageDelayed(Message msg, long delayMillis) 2 { 3 if (delayMillis < 0) { 4 delayMillis = 0; 5 } 6 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 7 }
關鍵代碼在sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
繼續:
1 //得到消息隊列 2 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 3 MessageQueue queue = mQueue; 4 if (queue == null) { 5 RuntimeException e = new RuntimeException( 6 this + " sendMessageAtTime() called with no mQueue"); 7 Log.w("Looper", e.getMessage(), e); 8 return false; 9 } 10 return enqueueMessage(queue, msg, uptimeMillis); 11 }
這段代碼主要就是獲取到消息隊列,有了消息隊列我們接着看enqueueMessage(queue, msg, uptimeMillis);
1 //handler和msg建立關聯 2 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 3 msg.target = this; 4 if (mAsynchronous) { 5 msg.setAsynchronous(true); 6 } 7 return queue.enqueueMessage(msg, uptimeMillis); 8 }
msg.target = this;這里將msg的target指向自己,msg的target只能是this
最后相信大家也看出來了,接下來就是真正將msg插入到消息隊列了
1 //負責將msg插入到消息隊列 2 boolean enqueueMessage(Message msg, long when) { 3 if (msg.target == null) { 4 throw new IllegalArgumentException("Message must have a target."); 5 } 6 7 synchronized (this) { 8 //將msg插入到消息隊列 9 10 msg.when = when; 11 Message p = mMessages; 12 boolean needWake; 13 //消息隊列為鏈式存儲 如果消息隊列中的消息為0,將msg插入到第一個,並新建一個message對象,將 14 //msg對象的next指向新建的message 等待新msg插入 15 if (p == null || when == 0 || when < p.when) { 16 // New head, wake up the event queue if blocked. 17 msg.next = p; 18 mMessages = msg; 19 needWake = mBlocked; 20 } else { 21 //將msg插入到隊尾 22 for (;;) { 23 prev = p; 24 p = p.next; 25 if (p == null || when < p.when) { 26 break; 27 } 28 if (needWake && p.isAsynchronous()) { 29 needWake = false; 30 } 31 } 32 msg.next = p; // invariant: p == prev.next 33 prev.next = msg; 34 } 35 36 37 } 38 return true; 39 }
繞了這么大一圈,最后是通過Handler中的消息隊列,將消息成功插入隊尾,至此handler在post的時候實際上
是將r封裝成了一個msg並插入到消息隊列;
另外這里再提一下Handler第二種方式即復寫handleMessage(Message msg)方法使用
handler.sendMessage(msg);
其源代碼其實就是執行以上的
1 public final boolean sendMessageDelayed(Message msg, long delayMillis) 2 { 3 if (delayMillis < 0) { 4 delayMillis = 0; 5 } 6 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 7 }
重復以上一系列過程,將msg插入到消息隊列;
最后我們來看一下比較關鍵的消息分發,消息分發是在以上Looper源碼的loop方法中核心方法是:
msg.target.dispatchMessage(msg);
我們知道msg的target只能是Handler本身,因此消息分發是在Handler中來完成的;
1 /** 2 * Handle system messages here. 3 */ 4 public void dispatchMessage(Message msg) { 5 if (msg.callback != null) { 6 handleCallback(msg); 7 } else { 8 if (mCallback != null) { 9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }
第一:if (msg.callback != null) 如果你傳入了callback即Runnable,那么就執行 handleCallback(msg);
即調用r的run方法,通常是handler.post(r);類型的
第二:if (mCallback != null)這種方法允許讓activity等來實現Handler.Callback接口,避免了自己編寫handler重寫handleMessage方法。
第三:handleMessage(msg); 即handler.sendMessage(msg);時調用的。直接回調Handler的handleMessage(msg);方法
至此,Android中的消息機制Looper和Handler相信你已經有了一定的了解;
最后我們再來總結一下
1、Looper 一個線程中只能有一個Looper,用來管理消息隊列
2、Looper從消息隊列里取出msg,交給Handler來進行分發,分發到Handler所在的線程執行,即創建Handler時的線程;
3、可以在當前線程中創建消息對象或直接復寫Runnable的run方法,同過Handler將msg和r封裝后的msg插入到消息隊列