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));
}
在创建looper对象的时候也创建了它要轮询的消息队列,并获取了当前线程的引用:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
由于线程和looper对象是一一对应的关系,所以我们有时候判断���前线程是否为UI线程的时候,会调用getMainLooper方法来判断:
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
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;// 获取到当前的消息队列
// 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,有可能会阻塞
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);
}
// 把从队列中取到的message交给handler来处理
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();
}
}
到此为止,在子线程中创建的message对象就被处理好了。下面我们需要谈论一下handler的泄露问题以及解决方法。
Handler泄露问题
谈论整个问题之前,我们需要了解JAVA的GC机制,这里就不做详细介绍了。当我们在activity中创建一个handler对象时,往往会继承一个匿名内部类,里面复写了handler的handleMessage方法。这时,该匿名内部类就会持有当前activity的对象引用。同时,持有该handler的子线程对象往往会进行一些耗时的操作,创建message对象并把handler对象的引用赋给它。此时如果用户关闭了activity,那么此activity对象是应该被系统回收的。但是,由于子线程的耗时操作,并且它和未处理的message对象都持有handler的引用,而handler又持有activity的引用,这就会导致该activity无法回收,出现内存泄露。