您的位置:首页 > 职场人生

Android面向面试复习----Handler详解

2018-02-04 13:43 441 查看

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中的所有任务给取消掉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: