在Android
中能夠經過Handler
來更新主線程中UI
的變化,更新UI
只能在主線程中進行更新,而爲了讓其餘線程也能控制UI
的變化,Android
提供了一種機制Handler
、Looper
與MessageQueue
一同協做來達到其餘線程更新UI
的目的。git
通常咱們會在主線程中經過以下方法定義一個Handler
github
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { tv.setText("mHandler change UI"); super.handleMessage(msg); } };
通常都見不到Looper
與MessageQueue
的,那麼它們都是在哪裏調用與如何協做的呢?在主線程不會顯式的調用Looper
而是會在ActivityThread.main
方法中默認調用。app
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("<pre-initialized>"); Looper.prepareMainLooper();//建立Looper 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();//開啓Looper循環 throw new RuntimeException("Main thread loop unexpectedly exited"); }
如上代碼,調用了Looper.prepareMainLooper()
方法,在主線程中建立了一個Looper
,不信的話咱們再查看該方法作了什麼async
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));//建立Looper並賦給sThreadLocal } /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
在prepareMainLooper
方法中調用了prepare
而經過prepare
會發現它其實就是建立了一個Looper
,並把它賦給了sThreadLocal
。同時能夠經過myLooper
方法獲取當前線程中的Looper
。再來看下new Looper(quitAllowed)
初始化了什麼ide
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
在這裏咱們終於看到了MessageQueue
了,它建立了一個MessageQueue
。該消息隊列就是用來保存後續的Message
。再回到ActivityThread.main
方法中,發現它調用了Looper.loop()
是用來開啓Looper
循環的,監聽消息隊列MessageQueue
中的消息。oop
咱們來看下Looper.loop()
的源碼:post
public static void loop() { final Looper me = myLooper();//獲取Looper 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.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg);//經過Handler分發消息 } 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(); } }
在loop
中首先獲取了當前所在線程的Looper
,同時也獲取到了Looper
中的MessageQueue
,說明Looper
已經與當前的線程進行了綁定。在後面開啓了一個for
的死循環,發現它作的事件是不斷的從消息隊列中取出消息,最後都交給msg.target
調用它的dispatchMessage
方法,那麼target
又是什麼呢?咱們進入Message
ui
/*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next;
發現它就是咱們熟悉的Handler
,說明最後調用的就是Handler
中的dispatchMessage
方法,對消息的分發處理。這樣一來Handler
就經過Looper
聯繫上了Looper
所綁定的線程,即爲主線程。this
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
經過Handler
的初始化,它獲取了它所處線程的Looper
,同時也獲取了Looper
中的消息隊列。固然若是所處線程的Looper
爲空的話就會拋出異常,這就解釋了爲何在非主線程中建立Handler
要分別調用Looper.prepare
與Looper.loop
而主線程則不須要,由於它默認已經調用了。spa
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } private static void handleCallback(Message message) { message.callback.run(); }
回到前面,對於dispatchMessage
的處理,首先判斷msg.callback
是否爲空,這裏callback
經過上面的Message
應該能知道他就是一個Runnable
,若是不爲空則直接調用Runnable
的run
方法。不然調用Handler
的handleMessage
方法.而這個方法相信你們已經很熟悉了,對事件的處理都是在這個方法中執行的。由於經過前面咱們已經知道了Handler
已經聯繫上了主線程,因此handleMessage
中的處理天然相對於在主線程中進行,天然也能更新UI
了。經過這裏咱們能把Looper
比做是一個橋樑,來鏈接Looper
所在的線程與Handler
之間的通訊,同時管理消息隊列MessageQueue
中的消息。那麼前面的Runnable
又是如何不爲空的呢?咱們使用Handler
有兩種方法,一種是直接建立一個Handler
而且重寫它的handleMessage
方法,而另外一種能夠經過Handler.post(Runnable)
來使用,這樣事件的處理天然就在run
方法中實現。
上面介紹了Handler
是如何聯繫上了須要操做的線程與對消息是如何取出與處理的。下面來談談消息是如何放入到Looper
中的MessageQueue
中的。
經過Handler
發送消息的方式不少,例如:sendMessage
、sendEmptyMessage
與sendMessageDelayed
等,其實到最後他們調用的都是sendMessageAtTime
方法。因此仍是來看下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); }
而sendMessageAtTime
則就是調用了enqueueMessage
操做,看這方法名就知道是入隊列操做了。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
果不其然直接調用了MessageQueue
中的queue.enqueueMessage(msg, uptimeMillis)
將消息加入消息隊列,同時這段代碼msg.target = this
將當前的Handler
賦給了msg.target
,這就是前面所說的Looper.loop
方法中調用的Handler
。這樣就把消息放到了MessageQueue
中,進而經過前面所講的loop
來取出消息進行相應的處理,這樣就構成了整個對消息進行處理的系統。這也是使用Handler
內部所發生的原理。好了Handler
、Looper
與MessageQueue
它們之間的聯繫基本就是這些了。我也簡單畫了張圖但願有所幫助
來總結下它們之間的流程。首先建立Handler
而在Handler
所處的線程中必需要有一個Looper
,若是在主線程中默認幫咱們實現了,其餘線程必須調用Looper.prepare
來建立Looper
同時調用Looper.loop
開啓對消息的處理。每一個Looper
中都有一個MessageQueue
它是用來存儲Message
的,Handler
經過post
或者send..
等一系列操做經過Looper
將消息放入到消息隊列中,而Looper
經過開啓一個無限的循環來一直監聽着消息的處理,不斷從MessageQueue
中取出消息,並交給與當前Looper
所綁定的handler
的dispatchMessage
進行分發,最後根據狀況調用Runnable
的run
或者Handler
的HandlerMessage
方法對消息進行最後的處理。
其它分享:https://idisfkj.github.io/arc...