在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...