本篇文章在android6.0基础上分析。
Looper在消息机制中扮演的角色是创造无限循环从Messagequeue中取得消息然后分发。
一、Looper的创建
只要调用Looper.prepare()方法之后,然后再Looper.loop()即可,这里两个方法都是static方法,表面没有任何Looper对象的参与,具体如何
先来看下prepare()这个方法:
public static void prepare() {
prepare(true);//调用私有方法
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");//限制Looper.prepare()只能调用一次
}
sThreadLocal.set(new Looper(quitAllowed));//这里才是Looper对象的创建,放入sThreadLocal中
}
<pre name="code" class="java"> private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创造了Messagequeue
mThread = Thread.currentThread();
}
代码中提到了sThreadLocal变量,类型为ThreadLocal,ThreadLocal的特殊作用在:可以多个线程共享,但set和get的作用域都是线程内的。例如thread-1和thread-2两个线程都调用了Loop.prepare(),使用的ThreadLocal是同一个对象,但set()放入的Looper是分别属于各自的。
二、Looper的loop()
先看源码,核心的地方被我加了注释。
public static void loop() {
final Looper me = myLooper();//从ThreadLocal中获取本线程的Looper对象,这个对象是用Looper.prepare创建的
if (me == null) {//如果没有Looper.prepare,就调用了loop就会抛出下面的异常
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 (;;) {//最重要的就是这个死循环,4.0之前是while(true)
Message msg = queue.next(); // might block,MessageQueue没有消息,执行next()就会线程阻塞,直到有消息为止。
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();
}
}
这个Loop是消息机制的核心所在,尤其是for(;;)这个死循环;上面代码关注四个点: (1)调用myLooper来判断是否已经用Looper.prepare()创建了Looper对象(ThreadLocal保存) (2)Loop循环每次都会从MessageQueue中获取一个Message(next()方法),如果没有则线程阻塞。 (3)如果获取了一个Message,则调用target(Hanlder)的dispatchMessage方法来分派处理这个Message。 (4)最后调用msg.recycleUnchecked(),来格式化这个Message,重新进入消息池;
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//如果是线程thread-1调用,则获得的thread-1的Looper,如果是thread-2调动,获得的是thread-2的looper。
}