Handler消息处理机制
一、核心類
1、Looper
1.變量
ThreadLocal sTreadLoad;
MesseageQuene mQueue;
Tread mThread;
2.操作集
Looper.Prepare();
Looper.loop();
2、Handler
變量
MessageQueue mQueue;
Looper mLooper;
CallBack mCallback;
操作集
//分發消息
dispatchMessage(Message msg);
//發送消息
sendMessage(Message msg)
3、Messeage
變量
int when;//發送時間(從開機到現在的時間,單位毫秒)
Handler target;//綁定的Handler對象
操作集
Handler getTarget();//獲取綁定的Handler對象
4、MesseageQueue
變量
Message mMessage;//鏈表的第一個節點
操作集
bolean enqueueMessage(Message msg, long when) ();//Messeage添加到鏈表 Message next() ;//從鏈表中取出Message
二、大體流程
使用Handler機制,首先需要在線程中調用Looper.prepare(),對Looper初始化,Looper初始化的同時,內部會對MessageQueue初始化,并持有MessageQueue對象;
創建Handler,并持有當前線程中Looper和MessageQueue的引用;
Handler對象發送消息,將發送的Messeage與Handler綁定,加入MessageQueue中的鏈表中;
Looper.loop()循環地取出Messeage,調用與Messeage綁定的Handler對象的dispatchMessage方法分發處理消息;
三、源碼分析
1.Looper的初始化
Looper.prepare源碼如下:
public static void prepare() {prepare(true);}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));} 復制代碼首先判斷當前Thread對應的Looper對象是否為空,如果不為空的話,拋出異常:每個線程中只能有一個Looper對象;如果不為空的話,新建一個Looper對象,并保存在一個Looper與創建它的Thread相對應的存儲結構ThreadLocal中,ThreadLocal的實現暫且不表。
繼續看new Looper(quitAllowed)的實現源碼:
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();} 復制代碼Looper的構造器中,創建類一個MesseageQueue對象,并獲取類當前線程; 這樣,Looper對象就持有MesseageQueue對象;
而我們都知道,在子線程中需要手動調用Looper的初始化,在主線程中是不需要我們手動調用Looper.prepare()和Looper.looper()方法的,因為系統已經調用過了,貼上調用源碼:
public static void main(String[] args) {//省略部分代碼Looper.prepareMainLooper();//省略部分代碼if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}復制代碼啟動的時候,ActivityThread的main()方法中調用了Looper.prepareMainLooper();main方法的末尾調用了Looper.loop()方法;
繼續查看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();}} 復制代碼首先調用了Looper的prepare方法進行初始化,然后用一個同步,給sMainLooper賦值;
2.Handler的初始化
使用Handler,當然要new 一個Handler對象,下面看一下Handler構造器的源碼:
public Handler(Callback callback, boolean async) {//省略部分代碼mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;} 復制代碼首先,會獲取到當前線程的Looper對象,如果Looper對象為空,拋出異常:在線程內沒有調用Looper.prepare(),不能創建Handler,這也就是之前說的,使用Looper機制,必須首先對looper進行初始化。
如果Looper對象不為空的話,獲取的Looper已經賦值給了mLooper,再獲取Looper中持有的MessageQueue對象(Looper初始化時創建)賦值給mQueue,這樣Handler就持有了當前線程的Looper對象和相應的MessageQueue對象,最后吧傳入的callback參數賦值給mCallBack;
3.Handler發送消息
Handler發送消息分為兩類,一類時sendMessage相關的,一類時post相關的;
首先查看sendMessage相關的方法源碼:
public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis);} 復制代碼可以看出最終都是調用sendMessageAtTime方法,sendMessage表示當前時間發送(SystemClock.uptimeMillis表示當前時間到開機時間的毫秒數),sendMessageDelayed的時間為當前時間在加上延遲的時間(delay的時間是負值是沒有意義的,不可能多長時間之前去處理消息,系統會修改為0),sendMessageAtTime如果輸入的時間參數小于當前時間,也會按照現在發送來處理。
然后查看post相關的源碼
public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}public final boolean postAtTime(Runnable r, long uptimeMillis){return sendMessageAtTime(getPostMessage(r), uptimeMillis);}private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;} 復制代碼很明顯,post最終也是調用sendMessage來實現的,只不過把Runnable參數賦值給了Message的callback變量(分發處理時用)。
4.Messeage如何與發送它的Handler綁定
sendMessageAtTime方法中,首先判斷MessageQueue是否為空,為空,拋出異常,返回;不為空,調用enqueueMessage(queue, msg, uptimeMillis);
繼續查看調用enqueueMessage的源碼:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);} 復制代碼首先把this,也就是Handler對象賦值給Message的target變量,target是Handler類型,這樣就實現了Messeage與發送它Handler的綁定。
然后調用queue.enqueueMessage方法,將Message加入MessageQueue中。
5.Messeage如何加入到MessageQueue中
繼續追蹤enqueueMessage的源碼,查看是如何將Message加入到MessageQueue中的:
boolean enqueueMessage(Message msg, long when) {//省略部分代碼synchronized (this) {//省略部分代碼msg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;needWake = mBlocked;} else {needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;}//省略部分代碼}return true;} 復制代碼5.1 將參數when賦值給了Messeag的when,這個when參數也就是我們sendMessageAtTime的那個時間參數;然后將Message p = mMessages(mMessage表示的是鏈表的頭節點)。
5.2 判斷p是否為null,如果是null的話,說明鏈表中沒有節點,也就是MessageQueue中沒有Message對象,直接把需要插入的msg做為頭節點賦值給mMessage,當然msg.next = null,表示msg后面沒有結點了,然后返回。
5.3 如果p不為null,那就需要將msg插入到鏈表的合適位置,一個結點插入到鏈表中很容易實現,關鍵是鏈表的結點是如何排序的。源碼中是否for循環,一直查找下一個結點,直到p == null 或 when < p.when是循環結束, p == null,也就是鏈表查找完畢,然后執行【msg.next = p;prev.next = msg】把msg插入到了鏈表的最后;when<p.when,也就是說查找到了比when小的Message對象,然后執行【msg.next = p;prev.next = msg】把msg插入到了pre結點和p結點之間。
5.4 總的來看,就是一個鏈表的插入結點過程,這個結點是以Message的when參數升序來進行排序的。
6.Looper如何從MessageQueue取出Message對象
Looper.loop()方法循環地從MessageQueue中取出Message對象,查看源碼:
public static void loop() {//省略部分代碼for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}//省略部分代碼try {msg.target.dispatchMessage(msg);dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}//省略部分代碼}} 復制代碼調用MessageQueue的next()方法,取出Message對象,如果為null,返回;如果不為null,調用msg.target.dispatchMessage(msg)分發消息(上面說到msg.target為發送該Message的Handler對象);
繼續查看MessageQueue的next方法源碼:
Message next() {//省略部分代碼for (;;) {//省略部分代碼synchronized (this) {// Try to retrieve the next message. Return if found.final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;if (msg != null) {if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// Got a message.mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}//省略部分代碼}}}復制代碼6.1 首先獲取到當前時間now,鏈表的頭節點mMessage賦值給msg;
6.2 如果now < msg.when,當前時間小于Message的when參數(即sendMessageDelay的時候設置了延遲,或者sendMessageAtTime設置了未來時間),鏈表是按when排序的,頭節點都比now大,其他結點當然更大,那么就計算出時間差,繼續執行for循環,直到now 大于等于msg.when,執行mMessages = msg.next(頭節點設置為下一個結點);msg.next = null, 然后返回msg,for循環結束(這里只分析了msg.target!=null的正常情況)
6.3 前面說過,sendMessageAtTime如果輸入的時間參數小于當前時間,符合這里的now > msg.when條件,會直接返回msg,進行分發處理。
7.Handler如何分發Message
繼續查看looper.loop方法,取出msg后,調用msg.target.dispatchMessage(msg),查看dispatchMessage方法的源碼:
public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}} 復制代碼7.1 判斷msg.callback參數是否為空,即handler.post(runnable)中的Runable參數,如果callback不為空,執行Handler的handlerCallBack(msg)方法,交由Runnable對象callback去處理消息,調用callback的run方法。
private static void handleCallback(Message message) {message.callback.run();} 復制代碼7.2 如果msg.callback為空,在判斷Handler的mCallBack方法是否為空,如果不為空的話(這個mCallBack,就是初始化Handler時,傳入的Handler.CallBack類型的參數,需要重寫handlerMessage方法),調用mCallBack的handlerMessage(msg)方法來處理。
7.3 如果msg.callback和Handler的mCallBack都為空的話,就去調用Handler的handlerMessage(msg)來處理。
轉載于:https://juejin.im/post/5bc44aff5188255c5644cccf
總結
以上是生活随笔為你收集整理的Handler消息处理机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springmvc 使用fastjson
- 下一篇: 想客户之所想 华为全栈云加速行业云化创新