Android Handler源码分析核心架构

时间:2019-01-18
本文章向大家介绍Android Handler源码分析核心架构,主要包括Android Handler源码分析核心架构使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言:

对于一个Android研发而言,亲身体会就是不管在平时开发或者面试的时候,Handler消息机制毋庸置疑都是一个必备的知识点,所以这边留一份个人笔记,如有分析不对的地方,还望指出!

目录:

1、如何分析Handler源码

2、源码大致流程:消息的入队与出队

3、从大致流程进入细化分析

3.1、Handler、Looper、MessageQueue三者之间的关系

3.2、Handler、Looper、MessageQueue之间的协作

总结图1:Handler在子线程中发送消息,消息会被添加到MessageQueue消息队列中,再来由Handler所处的当前线程的Looper来不断的轮询MessageQueue以获取出队消息,最后调用dispatchMessage进行消息传递给handleMessage进行处理

1、如何分析源码

众所皆知的Android源码的有很多,涉及到一个类或者多个类,一个类中又有很多代码,所以这边最简单的分析方式就是回归到Handler的使用中来,也就是如何使用Handler

1.1、实例一个Handler对象(主线程)

1.2、在子线程中使用Handler发送一个消息,如:handler.sendEmptyMessage(1)

1.3、消息发送出之后(执行1.2步骤),消息最终会被转发到我们new出来的Handler中的handleMessage方法进行处理(子线程消息发送到主线程中处理)

以上3个步骤即为我们对Handler的基本使用方式,所以,我们可以以发送消息的时机,作为源码分析的切入点,并留下一个疑问:

问题1:子线程发送的消息为什么是在主线程中接收的呢?

2、源码大致流程:消息的入队与出队

2.1、消息发送:sendMessage(Message msg) \ sendEmptyMessage(int what) \ postDelayed(Runnable r, long delayMillis) 等等

2.2、消息及发送时间处理:sendMessageAtTime(Message msg, long uptimeMillis)

2.3、消息队列添加:enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

2.4、消息出队:到这里,既然有消息添加到队列中的流程,而且我们最终都会获得相应的消息返回,那么消息是如何出队的呢?带着这个疑问,我们最终在MessageQueue 消息队列中找到一个函数名称为 next() 的函数。

问题2:这个next()函数 是在什么时候调用的呢?

在Handler源码上,以消息发送作为分析切入点来查看,如2.1罗列的几种消息发送方式,我们都可以很清楚的发现,消息都是调用了sendMessageDelayed(Message msg, long delayMillis),最终调用到sendMessageAtTime(Message msg, long uptimeMillis),然后在该方法里面调用了enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis),到这里,不管从方法名称还是局部变量的名称来看,这边都出现了一个队列的信息,所以可以知道Handler的消息发送最终是在sendMessageAtTime里面调用了MessageQueue.enqueueMessage()对消息进行队列添加,然后调用了MessageQueue.next()进行消息轮询并返回Message结果。

3、从大致流程进入细化分析

3.1、Handler、Looper、MessageQueue三者之间的 关系图2 如下:

在分析到第2步的sendMessageAtTime结束时,我们这边引出了一个消息队列的内容:MessageQueue queue = mQueue

复制代码
1 /**
2 * Enqueue a message at the front of the message queue, to be processed on
3 * the next iteration of the message loop. You will receive it in
4 * {@link #handleMessage}, in the thread attached to this handler.
5 * This method is only for use in very special circumstances – it
6 * can easily starve the message queue, cause ordering problems, or have
7 * other unexpected side-effects.

8 *
9 * @return Returns true if the message was successfully placed in to the
10 * message queue. Returns false on failure, usually because the
11 * looper processing the message queue is exiting.
12 */
13 public final boolean sendMessageAtFrontOfQueue(Message msg) {
14 MessageQueue queue = mQueue;
15 if (queue == null) {
16 RuntimeException e = new RuntimeException(
17 this + " sendMessageAtTime() called with no mQueue");
18 Log.w(“Looper”, e.getMessage(), e);
19 return false;
20 }
21 return enqueueMessage(queue, msg, 0);
22 }
23
24 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
25 msg.target = this;
26 if (mAsynchronous) {
27 msg.setAsynchronous(true);
28 }
29 return queue.enqueueMessage(msg, uptimeMillis);
30 }
复制代码
  问题:mQueue是什么东西?这个mQueue是怎么来的?所以我们在Handler的构造方法中找到了它的初始化位置

复制代码
1 /**
2 * Use the {@link Looper} for the current thread with the specified callback interface
3 * and set whether the handler should be asynchronous.
4 *
5 * Handlers are synchronous by default unless this constructor is used to make
6 * one that is strictly asynchronous.
7 *
8 * Asynchronous messages represent interrupts or events that do not require global ordering
9 * with respect to synchronous messages. Asynchronous messages are not subject to
10 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
11 *
12 * @param callback The callback interface in which to handle messages, or null.
13 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
14 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
15 *
16 * @hide
17 */
18 public Handler(Callback callback, boolean async) {
19 if (FIND_POTENTIAL_LEAKS) {
20 final Class<? extends Handler> klass = getClass();
21 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
22 (klass.getModifiers() & Modifier.STATIC) == 0) {
23 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
24 klass.getCanonicalName());
25 }
26 }
27
28 mLooper = Looper.myLooper();
29 if (mLooper == null) {
30 throw new RuntimeException(
31 “Can’t create handler inside thread that has not called Looper.prepare()”);
32 }
33 mQueue = mLooper.mQueue;
34 mCallback = callback;
35 mAsynchronous = async;
36 }
复制代码
  到此,从上面的两段源码,且带着第2点中,next()被调用的时机问题,我们引出了os/Handler中的两个成员变量

final Looper mLooper;
final MessageQueue mQueue;

MessageQueue 对象是从Looper中获得的,也就是说mQueue是在Looper中实例化的,所以很明显,Handler中的消息队列MessageQueue 是从轮询器Looper中获得的。

那么问题来了:为什么消息队列要在轮询器中进行实例化,请看以下源码

复制代码
1 /**
2 * Return the {@link MessageQueue} object associated with the current
3 * thread. This must be called from a thread running a Looper, or a
4 * NullPointerException will be thrown.
5 */
6 public static @NonNull MessageQueue myQueue() {
7 return myLooper().mQueue;
8 }
9
10 private Looper(boolean quitAllowed) {
11 mQueue = new MessageQueue(quitAllowed);
12 mThread = Thread.currentThread();
13 }
复制代码
  MessageQueue在Looper中进行实例化,也就是说一个Looper就有一个MessageQueue,属于绑定关系,从而得出一个Looper只能轮询一个消息队列

所以可得出如关系图2中Handler、Looper、MessageQueue三者的关系:Handler中持有Looper和MessageQueue,Looper中持有MessageQueue,而且Handler中的MessageQueue来自于Looper中的MessageQueue。

Handler是使用时通过New实例化出来的,MessageQueue是在Looper中进行实例的,那么这个Looper是如何实例化的?所以这边我们将引出 ActivityThread。而ActivityThread是什么东西呢?这边就稍微介绍一下:

安卓应用程序作为一个控制类程序,跟Java程序类似,都是有一个入口的,而这个入口就是ActivityThread的main函数:

复制代码
1 public static void main(String[] args) {
2 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “ActivityThreadMain”);
3 SamplingProfilerIntegration.start();
4
5 // CloseGuard defaults to true and can be quite spammy. We
6 // disable it here, but selectively enable it later (via
7 // StrictMode) on debug builds, but using DropBox, not logs.
8 CloseGuard.setEnabled(false);
9
10 Environment.initForCurrentUser();
11
12 // Set the reporter for event logging in libcore
13 EventLogger.setReporter(new EventLoggingReporter());
14
15 // Make sure TrustedCertificateStore looks in the right place for CA certificates
16 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
17 TrustedCertificateStore.setDefaultUserDirectory(configDir);
18
19 Process.setArgV0("");
20
21 Looper.prepareMainLooper();
22
23 ActivityThread thread = new ActivityThread();
24 thread.attach(false);
25
26 if (sMainThreadHandler == null) {
27 sMainThreadHandler = thread.getHandler();
28 }
29
30 if (false) {
31 Looper.myLooper().setMessageLogging(new
32 LogPrinter(Log.DEBUG, “ActivityThread”));
33 }
34
35 // End of event ActivityThreadMain.
36 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
37 Looper.loop();
38
39 throw new RuntimeException(“Main thread loop unexpectedly exited”);
40 }
复制代码
  以上的main函数代码中,我们还需要意识到两个问题:

1.我们之所以可以在Activity用Handler handler=new Handler()直接创建出来就默认绑定到主线程了,是因为上面的代码为我们做了绑定主线程的Looper的事情,

2.主线程的Looper是不能在程序中调用退出的,最后一句代码看到没,如果调用的话,就会抛出异常,退出主线程的循环是框架层在调用退出应用程序的时候才调用的

复制代码
1 /**
2 * Initialize the current thread as a looper, marking it as an
3 * application’s main looper. The main looper for your application
4 * is created by the Android environment, so you should never need
5 * to call this function yourself. See also: {@link #prepare()}
6 */
7 public static void prepareMainLooper() {
8 prepare(false);
9 synchronized (Looper.class) {
10 if (sMainLooper != null) {
11 throw new IllegalStateException(“The main Looper has already been prepared.”);
12 }
13 sMainLooper = myLooper();
14 }
15 }
16
17
18 private static void prepare(boolean quitAllowed) {
19 if (sThreadLocal.get() != null) {
20 throw new RuntimeException(“Only one Looper may be created per thread”);
21 }
22 sThreadLocal.set(new Looper(quitAllowed));
23 }
复制代码
  在ActivityThread的main中调用了 Looper.prepareMainLooper() -> prepare(false) -> sThreadLocal.set(new Looper(quitAllowed)), 这么一来,是不是执行到了上面的Looper构造函数中了?到这里,细心的人会发现这么一个问题:

问题3:Looper被实例化出来之后并没有直接返回,而是被set到了ThreadLocal中?

Handler与Looper是成对出现的,一个子线程发送消息,一个主线程接收消息,那么这边就涉及到了多线程,线程之间的通讯,是需要保证数据的安全,即数据隔离,所以使用到了ThreadLocal进行线程管理:如A线程在获取数据时只能获取A线程所控制的数据,而不能去获取到B线程中对应的数据,否则就会引起数据不同步,比如A线程数据被B线程数据所覆盖之类的问题,同时也验证了一个线程只能关联一个Looper对象。

所以问题3解决了。最后这个main的结尾,调用了 Looper.loop(); 进行轮询消息队列! 是不是很完美了?

3.2、Handler、Looper、MessageQueue之间的协作

通过前面的源码分析,我们已经知道了消息是如果添加到消息队列了。我们再来看消息的出队分析。

以下在Looper轮询器中的loop()中我们看到这样一句代码:Message msg = queue.next(); // might block

复制代码
1 /**
2 * Run the message queue in this thread. Be sure to call
3 * {@link #quit()} to end the loop.
4 */
5 public static void loop() {
6 final Looper me = myLooper();
7 if (me == null) {
8 throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
9 }
10 final MessageQueue queue = me.mQueue;
11
12 // Make sure the identity of this thread is that of the local process,
13 // and keep track of what that identity token actually is.
14 Binder.clearCallingIdentity();
15 final long ident = Binder.clearCallingIdentity();
16
17 for (;