标签:
下图表示了Handler、Looper、MessageQueue、Message这四个类之间的关系。
实际使用中通常在Activity中new Handler()创建一个Handler。之前说过,Handler必须与一个Looper关联,这个构造方法怎么没有给成员变量mLooper赋值?分析以下源码,可以看到通过调用Looper.myLooper()就可以获取当前线程的Looper。若获取不成功,则会抛出RuntimeException,创建Handler失败。获取成功后,就会给Handler的成员变量mLooper和mQueue赋值。
关于Looper.myLooper()的源码分析请参见Looper源码分析。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
// 这一块代码通过反射机制判断该继承与Handler的类是不是匿名内部类或成员类或局部类且不为static
// 若以上条件都满足,则会提示要将该Handler设为static,否则会内存泄露
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());
}
}
// 获取当前线程关联的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
// 若该线程没有Looper,则Handler无法创建
throw new RuntimeException(
"Can‘t create handler inside thread that has not called Looper.prepare()");
}
// Handler中的mQueue引用的就是Looper中的mQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
上面两个Handler构造方法有个不足,在哪个线程调用该构造方法,该Handler就必须与当前线程的Looper进行关联,所以Handler还提供了另外一个构造方法,该构造方法不管在哪个线程调用,可以与特定的Looper进行关联,源码如下:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handle有两组方法向MessageQueue发送Message。
分析以下源码可知,postRunnable先是创建一个Message,并将参数Runnable赋给Message的callback成员变量。两组方法最终调用的都是sendMessageAtTime。
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
// 这里将delay时间转换为了以boot时间为基准的时间,这样所有的Message有了同样的时间基准,从而可以排序
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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。方法先将该Handler的引用赋给msg的成员变量target,该target会在消息派发的时候起作用,它标识了该消息应该交给哪个Handler处理。最后调用MessageQueue.enqueueMessage方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在了解MessageQueue如何处理Message之前,先了解一下Message有哪些重要属性。
属性 | 意义 |
---|---|
int what | 用于指明消息类型 |
int arg1 int arg2 Object obj | 用于携带参数 |
Messenger replyTo | 用于跨进程通信 |
Handler target | 在消息派发时用于指明哪个handler处理消息 |
Runnable callback | 处理消息时执行的回调方法 |
long when | 用于指明何时派发消息 |
Message next | 指向下一个Message节点,用于构建消息链表 |
MessageQueue.enqueueMessage源码如下:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don‘t have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
首先判断Message的target是否为空,是否正在被使用,MessageQueue是否处于quiting状态,若是则会抛出异常。
以下代码片段为关键逻辑。
if (p == null || when == 0 || when < p.when) {
// 将消息插入链表头。
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don‘t have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 插入消息节点,但要保持链表按派发时刻先后的顺序排列
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
MessageQueue为一个消息链表,节点按消息派发时刻先后的顺序排列,p为Message链表头。
当MessageQueue为空时(p == null),或消息派发时刻为0(when == 0),或消息派发时刻早于消息链表头消息的派发时刻时,就将消息插入消息链表头。
反之,则遍历链表,寻找插入位置,将该消息插入链表。
消息循环Looper.loop()方法源码如下:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
queue.next()取出消息。
msg.target.dispatchMessage(msg)相当于handler.dispatchMessage(msg),派发消息,调用目标handler回调方法dispatchMessage。
消息处理回调方法源码如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
判断Message的callback是否不为空,当handler使用postRunnable时,参数Runnable就付给了msg.callback,这种情况就不为空,则会执行该callback。
判断mCallback时候为null,mCallback是Handler的成员变量,是在构造方法里赋值的,若不为空则执行mCallback.handleMessage(msg)。
当msg.callback和mCallback都为null时,执行handleMessage(msg)。
上述过程正是Android消息机制。
通常在这样的情况下使用Handler,由于在非UI线程不能执行更新UI操作,所以在非UI线程使用Handler发送更新UI消息,Handler在UI处理消息并执行更新UI操作。这个过程其实是要将方法的调用与方法的执行解耦。
发送更新UI消息相当于方法的调用
执行更新UI操作相当于方法的执行
这正是Active Object模式要解决的问题。
Active Object的概念在《Java编程思想》第4版中有所提及
第21章 并发
21.10 活动对象之所以称这些对象是“活动的”,是因为每个对象都维护着它自己的工作器线程和消息队列,并且所有对这种对象的请求都将进入队列排队,任何时刻都只能运行其中的一个。
一般情况下,一个对象调用其某个方法,该方法将会在当前线程中执行,即在哪个线程调用就在哪个线程执行,对象完全被动,无法控制方法的执行线程,所以一般的对象称为被动对象Passive Object。
而主动对象就不同了,它维护着自己的工作线程以及消息队列,不管在哪个线程调用主动对象的方法,调用请求都会进入队列排队,它自己的工作线程从消息队列中取出调用请求并执行,方法的调用与方法的执行解耦,并且方法的执行线程完全受自己控制,所以称为主动对象。
以Handler为例,Handler维护了一个Looper和一个消息队列MessageQueue,Looper决定了Handler在哪个线程处理消息,不管在哪个线程调用Handler.sendMessage(msg),消息处理程序都会在Looper所在线程中执行。
在Handler这个例子中,组成结构对应关系如下:
Proxy -> Handler.sendMessage()
Scheduler -> Looper
ActivationList -> MessageQueue
MethodRequest -> Message
ConcreteMethodRequest -> 不同的消息类型
Servant -> Handler的消息处理方法handleMessage
Android消息机制Handler、Looper、MessageQueue源码分析
标签:
原文地址:http://blog.csdn.net/sun927/article/details/51114644