摘要:在這里表示的是不允許退出。這之后會調(diào)用到進入實質(zhì)性的工作函數(shù)中。看到了吧,由于函數(shù)運行在主線程中,因此以上這些都是在主線程中運行的代碼。注意,這個是排他性的,如果前面的可以執(zhí)行就不會走后面的?,F(xiàn)在比較清楚了吧,整個消息循環(huán)是如何運轉(zhuǎn)的。
本來是不想寫這篇文章的,但是很早以前看過的東西容易遺忘,希望還是給自己一個記錄吧,另外此篇希望能夠?qū)懙纳钊胍恍?br>looper是什么就不介紹了吧,一個線程的消息泵,handler是消息的操作者,messagequeue是消息隊列。
我們從源頭開始看起,activity里的主ui線程就是ActivityThread mMainThread。這個ActivityThread的main函數(shù)會在程序創(chuàng)建的時候被調(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();這個是與普通線程創(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。在這里表示的是不允許退出。再來就是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)); }
存儲線程本地對象中一個新的looper。同時可以看到,如果已經(jīng)存在了這個線程本地對象,那么直接報錯,也就是說一個線程只允許一個looper存在。
回到ActivityThread的main,初始化好之后就是sMainThreadHandler = thread.getHandler();這個getHandler里直接返回的是mH,其實就是一個Handler的子類H。這個H是個很長的類,就是定義好的對activity默認(rèn)相應(yīng)的各項。
這之后會調(diào)用到Looper.loop();進入實質(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(); }
那么這個loop函數(shù)中就直接取過來用,后面是個死循環(huán),不斷的通過queue.next()獲取新的消息,并最終調(diào)用msg.target.dispatchMessage(msg);來處理。至此looper分析完了。下面看看Message的msg.target.dispatchMessage(msg);是怎么調(diào)用的:
看到message的時候,他的target就是Handler。這下子串上了吧,在looper的loop函數(shù)循環(huán)中枚舉新message,并交給message里的Handler的dispatchMessage函數(shù)處理。那么好吧,我們回顧下,在發(fā)送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(); }
看起來像鏈表是吧,每次取得時候?qū)Pool給m,sPool移動到下一個,然后將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)明白,其實就是個鏈表的應(yīng)用,保證sPool指向的是空閑的message的第一個。
然后呢,應(yīng)用的時候會調(diào)用Handler的sendMessage函數(shù),并且將參數(shù)設(shè)置為剛才獲取到的空閑message,對吧。那么我們看看這個sendMessage,最終會調(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,然后會走到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這個函數(shù)中,會走到msg.target.dispatchMessage(msg);這句話,實際上就是在走h(yuǎn)andler的msg.target.dispatchMessage。再進入到handler中看看這個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,如果沒有則試圖調(diào)用自身的mCallback的handleMessage,如果還沒有,好吧,直接走h(yuǎn)andleMessage。依次看一下,首先是handleCallback:
private static void handleCallback(Message message) { message.callback.run(); }
這個callback是個什么呢?可以通過Message的obtain看到:
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
一個runnable,那么這個runnable是何時被賦值的呢?看Handler中:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
看到了吧,這里在執(zhí)行post的時候給的runnable就是這個callback。那么再想想,我們在寫代碼的時候,很多時候都會走一個handler的post或者postDelayed,執(zhí)行一段代碼在主線程中,這個傳遞進來的runnable就是message的callback了。順便說下,View里的post也是調(diào)用的這個東西。
下面是Handler自身的mCallback了,在構(gòu)造Handler的時候可以指定一個callback傳遞進來,這個Callback是這樣定義的:
public interface Callback { public boolean handleMessage(Message msg); }
指定的話就會走這個標(biāo)準(zhǔn)的回調(diào),否則最后會走Handler的handleMessage,這個才是我們最常用的繼承下來的函數(shù)??吹搅税?,由于loop函數(shù)運行在主線程中,因此以上這些都是在主線程中運行的代碼。注意,這3個是排他性的,如果前面的可以執(zhí)行就不會走后面的。
現(xiàn)在比較清楚了吧,整個消息循環(huán)是如何運轉(zhuǎn)的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/66767.html
摘要:輔助功能類,提供接口向消息池中發(fā)送各類消息事件,并且提供響應(yīng)消息的機制。進入消息泵循環(huán)體,以阻塞的方式獲取待處理消息。執(zhí)行消息的派發(fā)。并且將返回值保存在了。我們深入下去看看層的部分,在這里明顯生成了一個新的,并且將地址作為返回值返回了。 概述 android里的消息機制是非常重要的部分,這次我希望能夠系統(tǒng)的剖析這個部分,作為一個總結(jié)。首先這里涉及到幾個部分,從層次上看,分為java層和...
摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。也稱之為消息隊列,特點是先進先出,底層實現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)得出結(jié)論方法初始話了一個對象并關(guān)聯(lián)在一個對象,并且一個線程中只有一個對象,只有一個對象。 目錄介紹 1.Handler的常見的使用方式 2.如何在子線程中定義Handler 3.主線程如何自動調(diào)用Looper.prepare() 4.Looper.prepare()方法源碼分析...
摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。子線程往消息隊列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。 目錄介紹 1.Handler的常見的使用方式 2.如何在子線程中定義Handler 3.主線程如何自動調(diào)用Looper.prepare() 4.Looper.prepare()方法源碼分析 5....
摘要:通過向消息池發(fā)送各種消息事件通過處理相應(yīng)的消息事件。消息泵通過不斷地從中抽取,按分發(fā)機制將消息分發(fā)給目標(biāo)處理者。也稱之為消息隊列,特點是先進先出,底層實現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)。目錄介紹 6.0.0.1 談?wù)勏C制Hander作用?有哪些要素?流程是怎樣的?簡單說一下你的看法! 6.0.0.2 為什么一個線程只有一個Looper、只有一個MessageQueue,可以有多個Handler? 6...
閱讀 3146·2021-09-28 09:43
閱讀 978·2021-09-08 09:35
閱讀 1505·2019-08-30 15:56
閱讀 1251·2019-08-30 13:00
閱讀 2793·2019-08-29 18:35
閱讀 1896·2019-08-29 14:07
閱讀 3536·2019-08-29 13:13
閱讀 1401·2019-08-29 12:40