Handler详解
这篇文章缘起于一道面试题:
Android面试题 请解释下单线程模型中Message、Handler、MessageQueue、Looper之间的关系
虽然能够大致说明白,但是自己对答案也不太满意,翻一翻源码,从源码角度剖析一番。
1. 概述Handler相关对象模型关系
首先看一下Handler、Looper、MessageQueue、Message的相关类图
Handler中有两个成员变量:mLooper、mQueue,分别对应的是Looper和MessageQueue的实例。
Looper中包含一个成员变量mQueue,对应的是MessageQueue的实例。
在创建Handler的时候会获取当前线程的Looper,并将Looper对应的消息队列也赋值给Handler中的mQueue,用来存储消息。Handler的构造方法
平时我们都是new Handler()创建,最后还是调用的两个参数的构造方法
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; }
在构造方法中通过
mLooper = Looper.myLooper();
创建了Looper。- myLooper方法中是从sThreadLocal中获取的Looper:sThreadLocal.get()
Looper是在什么地方创建的呢?答案是prepare中,所以在子线程中,没有调用Looper.prepare()不能创建Handler,而主线程默认执行了Looper.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)); }
- sThreadLocal是跟线程相关的,所以,每个线程可以对应一个Looper及MessageQueue
通过Looper,获取到了Looper对应的MessageQueue,并赋值给Handler中的MessageQueue
这样就把Handler和Looper、MessageQueue串联了起来。
2. 从源码角度剖析3个流程
发送消息
发送消息有两种方式:
sendMessage(Message msg)
,或者post(Runnable r)
,最终都是调用到了sendMessageAtTime(Message msg, long uptimeMillis)
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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
其中最关键的是
queue.enqueueMessage(msg, uptimeMillis)
消息队列把Message放到了消息队列中,存储起来。分发消息
Looper调用了loop()方法之后,就会不停的从MessageQueue中读取消息,只要读取到消息,就会进行分发处理。下面我们把loop()中读取消息,分发处理逻辑摘出来。
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); } } ... }
其中:
Message msg = queue.next();
从消息队列中取出消息
如果消息不为空,则使用Handler的dispatchMessage方法进行分发处理。public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
这里主要有两个分支:
handleCallback(msg)
是处理的Runnable任务handleMessage(msg)
是处理的普通消息任务
处理消息
处理消息就是执行HandleMessage中的逻辑或者Runnable中的逻辑。
在看Looper.loop()方法逻辑的时候,最后一行被我删掉了,这一行是等消息分发处理完后对msg的回收处理。
msg.recycleUnchecked();
源码如下:
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++; } } }
3. 文章开头的面试题答案整理
工作流程:
- 在单线程中,Looper轮询器被调用prepare()和loop()后,它会不断的从MessageQueue头部读取Message;
- 创建Handler时,Handler内部会持有当前线程对应的Looper和MessageQueue的引用。
- 如果该线程中有Handler发送消息给MessageQueue,Looper就能够取出该消息,通过Message的target(Handler)的dispathMessage,进行处理(两个分支,一个处理Runnable,一个处理普通Message)。
- 处理完成后,Looper又继续进行消息的拉取,如此循环往复。直到调用
removeCallbacksAndMessages
可以将当前Handler中的所有任务给取消掉。