摘要:在這里表示的是不允許退出。這之后會(huì)調(diào)用到進(jìn)入實(shí)質(zhì)性的工作函數(shù)中。看到了吧,由于函數(shù)運(yùn)行在主線程中,因此以上這些都是在主線程中運(yùn)行的代碼。注意,這個(gè)是排他性的,如果前面的可以執(zhí)行就不會(huì)走后面的?,F(xiàn)在比較清楚了吧,整個(gè)消息循環(huán)是如何運(yùn)轉(zhuǎn)的。
本來(lái)是不想寫這篇文章的,但是很早以前看過(guò)的東西容易遺忘,希望還是給自己一個(gè)記錄吧,另外此篇希望能夠?qū)懙纳钊胍恍?br>looper是什么就不介紹了吧,一個(gè)線程的消息泵,handler是消息的操作者,messagequeue是消息隊(duì)列。
我們從源頭開始看起,activity里的主ui線程就是ActivityThread mMainThread。這個(gè)ActivityThread的main函數(shù)會(huì)在程序創(chuàng)建的時(shí)候被調(diào)用,那么看下內(nèi)部:
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0(""); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
首先走了Looper.prepareMainLooper();這個(gè)是與普通線程創(chuàng)建looper不同的地方,普通的都是prepare方法調(diào)用。那么看看里面:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
還是prepare,但是傳遞的參數(shù)是false。在這里表示的是不允許退出。再來(lái)就是prepare:
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)); }
存儲(chǔ)線程本地對(duì)象中一個(gè)新的looper。同時(shí)可以看到,如果已經(jīng)存在了這個(gè)線程本地對(duì)象,那么直接報(bào)錯(cuò),也就是說(shuō)一個(gè)線程只允許一個(gè)looper存在。
回到ActivityThread的main,初始化好之后就是sMainThreadHandler = thread.getHandler();這個(gè)getHandler里直接返回的是mH,其實(shí)就是一個(gè)Handler的子類H。這個(gè)H是個(gè)很長(zhǎng)的類,就是定義好的對(duì)activity默認(rèn)相應(yīng)的各項(xiàng)。
這之后會(huì)調(diào)用到Looper.loop();進(jìn)入實(shí)質(zhì)性的工作函數(shù)中。
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn"t called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn"t corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
首先看到在Looper的構(gòu)造函數(shù)里就創(chuàng)建了MessageQueue:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
那么這個(gè)loop函數(shù)中就直接取過(guò)來(lái)用,后面是個(gè)死循環(huán),不斷的通過(guò)queue.next()獲取新的消息,并最終調(diào)用msg.target.dispatchMessage(msg);來(lái)處理。至此looper分析完了。下面看看Message的msg.target.dispatchMessage(msg);是怎么調(diào)用的:
看到message的時(shí)候,他的target就是Handler。這下子串上了吧,在looper的loop函數(shù)循環(huán)中枚舉新message,并交給message里的Handler的dispatchMessage函數(shù)處理。那么好吧,我們回顧下,在發(fā)送message的時(shí)候,一般先obtain獲取一個(gè)消息,我們看看:
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(); }
看起來(lái)像鏈表是吧,每次取得時(shí)候?qū)Pool給m,sPool移動(dòng)到下一個(gè),然后將sPoolSize減一,最后返回m。再看下回收部分:
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
這里將自己賦值給sPool,然后sPoolSize++,看到這里應(yīng)當(dāng)明白,其實(shí)就是個(gè)鏈表的應(yīng)用,保證sPool指向的是空閑的message的第一個(gè)。
然后呢,應(yīng)用的時(shí)候會(huì)調(diào)用Handler的sendMessage函數(shù),并且將參數(shù)設(shè)置為剛才獲取到的空閑message,對(duì)吧。那么我們看看這個(gè)sendMessage,最終會(huì)調(diào)用到sendMessageAtTime中:
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); }
這里出現(xiàn)了MessageQueue,然后會(huì)走到enqueueMessage:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
第一句就是msg.target = this;,清楚了吧,這里將message的target賦值為handler自身。那么回到loop這個(gè)函數(shù)中,會(huì)走到msg.target.dispatchMessage(msg);這句話,實(shí)際上就是在走h(yuǎn)andler的msg.target.dispatchMessage。再進(jìn)入到handler中看看這個(gè)dispatchMessage:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
能看到什么?先試圖調(diào)用message的callback,如果沒(méi)有則試圖調(diào)用自身的mCallback的handleMessage,如果還沒(méi)有,好吧,直接走h(yuǎn)andleMessage。依次看一下,首先是handleCallback:
private static void handleCallback(Message message) { message.callback.run(); }
這個(gè)callback是個(gè)什么呢?可以通過(guò)Message的obtain看到:
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
一個(gè)runnable,那么這個(gè)runnable是何時(shí)被賦值的呢?看Handler中:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
看到了吧,這里在執(zhí)行post的時(shí)候給的runnable就是這個(gè)callback。那么再想想,我們?cè)趯懘a的時(shí)候,很多時(shí)候都會(huì)走一個(gè)handler的post或者postDelayed,執(zhí)行一段代碼在主線程中,這個(gè)傳遞進(jìn)來(lái)的runnable就是message的callback了。順便說(shuō)下,View里的post也是調(diào)用的這個(gè)東西。
下面是Handler自身的mCallback了,在構(gòu)造Handler的時(shí)候可以指定一個(gè)callback傳遞進(jìn)來(lái),這個(gè)Callback是這樣定義的:
public interface Callback { public boolean handleMessage(Message msg); }
指定的話就會(huì)走這個(gè)標(biāo)準(zhǔn)的回調(diào),否則最后會(huì)走Handler的handleMessage,這個(gè)才是我們最常用的繼承下來(lái)的函數(shù)??吹搅税?,由于loop函數(shù)運(yùn)行在主線程中,因此以上這些都是在主線程中運(yùn)行的代碼。注意,這3個(gè)是排他性的,如果前面的可以執(zhí)行就不會(huì)走后面的。
現(xiàn)在比較清楚了吧,整個(gè)消息循環(huán)是如何運(yùn)轉(zhuǎn)的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66767.html
摘要:輔助功能類,提供接口向消息池中發(fā)送各類消息事件,并且提供響應(yīng)消息的機(jī)制。進(jìn)入消息泵循環(huán)體,以阻塞的方式獲取待處理消息。執(zhí)行消息的派發(fā)。并且將返回值保存在了。我們深入下去看看層的部分,在這里明顯生成了一個(gè)新的,并且將地址作為返回值返回了。 概述 android里的消息機(jī)制是非常重要的部分,這次我希望能夠系統(tǒng)的剖析這個(gè)部分,作為一個(gè)總結(jié)。首先這里涉及到幾個(gè)部分,從層次上看,分為java層和...
摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。也稱之為消息隊(duì)列,特點(diǎn)是先進(jìn)先出,底層實(shí)現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)得出結(jié)論方法初始話了一個(gè)對(duì)象并關(guān)聯(lián)在一個(gè)對(duì)象,并且一個(gè)線程中只有一個(gè)對(duì)象,只有一個(gè)對(duì)象。 目錄介紹 1.Handler的常見的使用方式 2.如何在子線程中定義Handler 3.主線程如何自動(dòng)調(diào)用Looper.prepare() 4.Looper.prepare()方法源碼分析...
摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。 目錄介紹 1.Handler的常見的使用方式 2.如何在子線程中定義Handler 3.主線程如何自動(dòng)調(diào)用Looper.prepare() 4.Looper.prepare()方法源碼分析 5....
摘要:通過(guò)向消息池發(fā)送各種消息事件通過(guò)處理相應(yīng)的消息事件。消息泵通過(guò)不斷地從中抽取,按分發(fā)機(jī)制將消息分發(fā)給目標(biāo)處理者。也稱之為消息隊(duì)列,特點(diǎn)是先進(jìn)先出,底層實(shí)現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)。目錄介紹 6.0.0.1 談?wù)勏C(jī)制Hander作用?有哪些要素?流程是怎樣的?簡(jiǎn)單說(shuō)一下你的看法! 6.0.0.2 為什么一個(gè)線程只有一個(gè)Looper、只有一個(gè)MessageQueue,可以有多個(gè)Handler? 6...
閱讀 3082·2021-09-28 09:43
閱讀 917·2021-09-08 09:35
閱讀 1453·2019-08-30 15:56
閱讀 1199·2019-08-30 13:00
閱讀 2744·2019-08-29 18:35
閱讀 1839·2019-08-29 14:07
閱讀 3450·2019-08-29 13:13
閱讀 1344·2019-08-29 12:40