android中非常重要的一个消息通信机制handler,可以理解为是android进程内部的一种消息通信机制,通过消息队列,提高系统的并发性。
根据上图,可以看出,handler消息队列的核心是looper,其实Looper实质是一个“绑定”到某个线程的无限循环,该循环不停的从消息队列中取出消息,并且分发给该消息对应的target,也就是一个Handler来实际的分发处理该消息。那么我们先来看一看Looper的真实面目。根据代码段来分析
public class Looper{
private static final String TAG ="Looper";
// sThreadLocal.get() will return nullunless you've called prepare().
static final ThreadLocal<Looper>sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
......
}
首先looper会初始化一个静态的线程局部变量,那么这个线程局部变量意欲何为呢,下面看一些prepare(......)这个方法
public staticvoid prepare() {
prepare(true);
}
private static void prepare(booleanquitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Onlyone Looper may be created per thread");
}
sThreadLocal.set(newLooper(quitAllowed));
}
根据prepare()方法的代码可以看出,该公共方法会调用Looper类的一个私有的方法prepare(boolean quitAllowed),从这个方法里,我们应该可以看出sThreadLocal这个线程局部变量的作用了,对了,没错,你肯定猜出来啦,就是为了将一个Looper对象绑定到当前线程中,就是为了线程的并发访问,如此简单而已。那么类Looper的构造方法做了什么呢?
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
这个方法的主要工作就是生成了一个消息队列的对象,并且初始化mThread为当前进程,那么这个mThread是用来做什么的呢,这个可以根据Looper类的一个公共成员方法getThread()方法来推测,这个方法应该是用于ThreadLocal这个类的内部来使用,可能是作为一个key,来存储Looper对象。
所以说,当你想在一个线程中绑定一个Looper对象时,肯定要首先调用Looper类的静态公共方法prepare()。那么你可能现在会问了,你不是说,会将一个无限循环绑定到当前线程中,别着急,下面就是了,
public staticvoid loop() {
① final Looper me =myLooper();
if (me == null) {
throw new RuntimeException("NoLooper; Looper.prepare() wasn't called on this thread.");
}
② final MessageQueuequeue = me.mQueue;
// Make sure the identity of thisthread is that of the local process,
// and keep track of what that identitytoken actually is.
Binder.clearCallingIdentity();
final long ident =Binder.clearCallingIdentity();
③ for (;;) {
Message msg = queue.next(); //might block
if (msg == null) {
// No message indicates thatthe message queue is quitting.
return;
}
// This must be in a localvariable, 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);
}
......
⑤ msg.recycle();
}
}
这又是一个类的静态公共方法,所以对于Looper类来说,当你在某个线程中调用Looper类中的方法时,都是通过类名来调用的,而不是通过Looper的对象来调用,因为生成Looper对象是由prepare这个公共方法在类的内部来实现的。
从上面的编号1处的代码段可以知道,该方法首先会判断是否可以通过sThreadLocal来获取当前进程的Looper类对象,如果获取失败,则跑出异常,这个异常是说当前进程没有调用Looper.prepare()方法,从这里,我们也可以推断,在一个进程中,prepare方法肯定要在loop()方法之前被调用。
编号2处的代码段是获取消息队列的对象。
编号3处的代码则是进入了一个无限的for循环,这个for循环就是从消息队列中取出消息,
编号4则是这个过程的中心环节了,通过获取msg的target成员变量(也就是一个handler对象),然后通过该变量调用disapatchMessage(msg)来分发处理消息。
编号5则是用于回收处理过的消息对象。
以上简单分析了Looper的实现原理,下面一节,将会进一步分析Handler的消息机制。由于个人水平有限,如有错误,敬请指正!