Message,Handler是在Android中最常用的,更新UI点手段。与其他图形界面的原理类似,Android系统中UI也是靠消息驱动来工作的,具体有以下一些概念。
消息发送者:发生消息到队列
消息队列:存储消息的队列
消息循环:不断的循环取出消息,发给处理者
消息处理者:处理消息
他们的关系可以画成下图的样子:
消息机制原理图
消息循环Looper
Android消息循环由Looper类来实现。使用Looper要经过以下两个方法。
Looper.prepare();
Looper.loop();
在Activity主线程中查看就有Looper的初始化,查看ActivityThread类的main方法中,有下列代码
查看prepareMainLooper()方法第一句就调用了prepare方法。归根结底Looper的调用顺序先要调用prepare方法,然后再调用loop()方法。
1.Looper.prepare()
那我们先查看Looper的prepare方法
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
// 保证一个线程Looper只能调用一次
// ThreadLocal并不是一个Thread,而是Thread的局部变量,
// 也许把它命名为ThreadLocalVariable更容易让人理解一些。
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
该方法很简单就是创建了一个Looper对象存入sThreadLocal中。
注意:ThreadLocal调用set存储,调用get获取。普通对象当在不同线程中获取时候是同一个对象,数据相同。然而ThreadLocal不同线程调用这个get,set获取到的数据是不同的,它是线程相关的局部变量。
综上一个线程只能存储一个Looper对象。
查看下Looper的构造函数。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
构造函数主要就是创建了一个MessageQueue。
用图概括下
Looper.prepare()工作流程
prepare方法主要就是创建了Looper对象存在当前线程,同时Looper内创建了一个MessageQueue。
1.Looper.loop()
先看loop的源码
public static void loop() {
//取出当前线程相关的looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取当前线程Looper对象内的MessageQueue(消息队列)
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();
}
}
查看loop方法,主要就是开启了消息循环,内部就是一个for循环一直获取一个个的Message调用msg.target.dispatchMessage处理。
1.获取调用线程的Looper对象,获取Looper对象内的MessageQueue
2.循环调用MessageQueue的next方法获取下一个元素
3.最终调用target的dispatchMessage方法处理Message。
4.继续步骤2
Looper.loop()工作流程
消息队列MessageQueue
MessageQueue主要提供了向队列插入Message的方法,获取下一个Message的方法。其类内部的成员变量
final MessageQueue mQueue;
为一个链表,存储所有的Message看下Message链表的结构应该是下图的样子
整个队列按照when变量从小到大排序,next变量指向下一个节点,其中的callback与target是消息最终的处理者。
上一节主要讲了loop方法内有个for循环,for内部会一直获取下一条Message。这里就看以下这个next方法。
MessageQueue的next方法是获取队列中的下一条Message
Message