1. 四个部分:
1) Message:在不同线程之间传递消息,可以在内部携带少量的信息。
2) Handler:主要用于发送处理消息的。发送消息:sendMessage()方法,处理消息:handlerMessage()方法
3) MesssageQueue:消息队列,主要用于存放所有通过Handler发送的消息。每个线程都只有一个MessageQueue对象。
4) Looper:是每个线程的MesssageQueue的管家,调用Looper的loop方法后,就会进入到一个无限循环当中,每当发现MessageQueue中存在一个消息,就会将它取出,并传递到Handler中的handleMessage()方法中。每个线程中只会有一个Looper对象。
2. Handler类中的重要方法
1) handlerMessage()方法:在Handler类此方法为空方法,子类需要实现该方法,实现处理接收到的消息的具体的逻辑。
<span style="font-size:18px;">/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}</span>
2) dispatchMessage ()方法:在Looper类中的loop方法中会回调此方法
<span style="font-size:18px;"> msg.target.dispatchMessage(msg);</span>
msg为Message类的对象,它的成员变量target实际上就是一个Handler对象
<span style="font-size:18px;">/*package*/ Handler target;</span>
再看dispatchMessage方法的实现:
<span style="font-size:18px;"> public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
<span style="color:#ff0000;"> handleMessage(msg);</span>
}
}</span>
着重看我们用红色圈出的代码,就是调用了我们前面所说的用来实现具体的处理消息的逻辑。
3) publicHandler(Callback callback, boolean async)
<span style="color:#0070c0;">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());
}
}
</span><span style="color:#ff0000;">mLooper = Looper.myLooper();</span><span style="color:#0070c0;">
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
</span><span style="color:#ff0000;">mQueue = mLooper.mQueue;</span><span style="color:#0070c0;">
mCallback = callback;
mAsynchronous = async;
}</span>
接着看这段代码,同样只关注红笔圈出的代码,实际上分别给我们的Handler中的Looper实例和MessageQueue实例赋值,这样,Handler就与Looper和MessageQueue建立了联系。(因为利用Handler发送消息时要和MessageQueue打交道,而从消息队列中取出消息时Handler需要和Looper打交道)
4) sendMessage()方法
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
可以对这段代码一直向下追踪,最后这里追踪到这段代码停下来:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
<span style="color:#ff0000;">msg.target = this;</span>
if (mAsynchronous) {
msg.setAsynchronous(true);
}
<span style="color:#ff0000;">return queue.enqueueMessage(msg, uptimeMillis);</span>
}
有两行代码值得我们去关注
a. 第一个将msg.target赋值为this,还记得我们前面所说的这个target就是一个Handler类对象,在Looper类的loop方法中会调用这个target的dispatchMessage()方法。原来是在这里建立了联系,然后才能够在loop方法中去调用到dispatchMessage方法。
b. 调用了queue.enqueueMessage()方法。首先必须注意,此时已经跳出了Handler类的职能,也就是说调用的不再是Handler类中的方法,而是MessageQueue中的方法。这里的queue,实际上就是我们前面在Handler的构造方法中提到和Handler类建立联系的MessageQueue(不信可以返回到上一层函数调用)。到此,我们的分析流程就跳到MessageQueue的enqueueMessage()方法。下面就介绍MessageQueue类中的重要的方法。
3. MessageQueue类
1) 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) {
<span style="color:#ff0000;"> 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;
}</span>
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) {
<span style="color:#ff0000;"> nativeWake(mPtr);</span>
}
}
return true;
}
咱们只关注synchronized中的代码。
a.
如果mQuitting为true,则会进入这个条件语句,再注意红笔圈出的代码,从函数看出,这就是在回收消息。因为实际上底层维护了一个消息池,使用结束后要将资源归还到池中。
b.
这段代码实际上是在执行将我们的消息插入到MessageQueue中。(实际上MessageQueue本身并不维护这个消息队列,注意紧跟这段代码之后的nativeWake()方法,这是一个JNI函数,其内部会将mMessages消息添加到C环境中的消息队列中)。
2) next()-----取出消息
nativePollOnce(ptr, nextPollTimeoutMillis);
这里注意这样一行代码就行了,同样这里是一个JNI函数,其作用就是从消息队列中取出一个消息。
4. Looper类
1) Looper的私有构造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
这个构造方法是用private关键字修饰的,意味着我们是无法通过构造方法new 出一个实例的。稍微有点Java经验的开发人员很快就会意识到这里面使用了单例模式,保证一个Thread只对应一个Looper对象。
2) 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));
}
可以看到,在prepare()方法中new出了一个Looper实例,并将它设置到线程局部存储变量中。对于线程局部存储变量感兴趣的读者可自行查阅相关资料,这里我就不说明,再说我也说不好。再追踪到sThreadLocal.set()方法中:
下面是Thread.currentThread()的实现:
public void set(T value) {
<span style="color:#ff0000;"> Thread currentThread = Thread.currentThread();</span>
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
查看它的注释:返回调用者线程,即当前线程。
那么,到这里,我们是不是能够得出一个结论:线程和我们的Looper对象是在这里建立联系的。
3) loop()方法
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
<span style="color:#ff0000;">final Looper me = myLooper();</span>
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
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();
}
}
注意红笔圈出的代码,这里调用myLooper()方法返回当前的线程的Looper对象,其实现代码如下:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
接着进入如下这段for循环
for (;;) {
<span style="color:#ff0000;"> Message msg = queue.next(); // might block</span>
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
<span style="color:#ff0000;"> msg.target.dispatchMessage(msg);</span>
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();
}
看到没有,在这里调用了我们前面在MessageQueue中分析的next()方法,即在此处取出消息,注意旁边的注释,可能会阻塞。实际上此时如果当前队列为空,则当前线程会被挂起。好!取出了消息,接下来的是不是应该去处理啊!把目光投到第二处红笔圈出的代码,是不是似曾相识?实际上我们在前面介绍Handler类时就截取过这段代码,这里应该不用我作过多解释了吧。