Android源码学习(2) Handler之Looper

Looper准备

Handler实例化时,会从当前线程获取Looper,从而获得MessageQueue,用于发送消息。然而,线程不是生来就有Looper对象的,需要在线程执行中调用静态方法Looper.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));
}

静态变量sThreadLocal是范型类ThreadLocal<Looper>的实例,用于保存线程与其Looper之间的映射关系:sThreadLocal以自身为key,将Looper实例放入当前线程的ThreadLocalMap中(字段名为threadlocals,ThreadLocalMap底层是通过hash表实现的)。由于任何线程存放Looper都是以sThreadLocal为key,所以任意线程最多只能有一个Looper。

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;
    }
    return setInitialValue();
}

Looper循环

准备完成之后,通过调用Looper.loop()进入looper循环。Looper在死循环中,不断从MessageQueue中获取消息,交给Handler的dispatchMessage进行处理。loop函数的关键代码是黄色背景标记的区域:

 1 public static void loop() {
 2     final Looper me = myLooper();
 3     if (me == null) {
 4         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
 5     }
 6     final MessageQueue queue = me.mQueue;
 7 
 8     // Make sure the identity of this thread is that of the local process,
 9     // and keep track of what that identity token actually is.
10     Binder.clearCallingIdentity();
11     final long ident = Binder.clearCallingIdentity();
12 
13     for (;;) {
14         Message msg = queue.next(); // might block
15         if (msg == null) {
16             // No message indicates that the message queue is quitting.
17             return;
18         }
19 
20         // This must be in a local variable, in case a UI event sets the logger
21         final Printer logging = me.mLogging;
22         if (logging != null) {
23             logging.println(">>>>> Dispatching to " + msg.target + " " +
24                     msg.callback + ": " + msg.what);
25         }
26 
27         final long traceTag = me.mTraceTag;
28         if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
29             Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
30         }
31         try {
32             msg.target.dispatchMessage(msg);
33         } finally {
34             if (traceTag != 0) {
35                 Trace.traceEnd(traceTag);
36             }
37         }
38 
39         if (logging != null) {
40             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
41         }
42 
43         // Make sure that during the course of dispatching the
44         // identity of the thread wasn't corrupted.
45         final long newIdent = Binder.clearCallingIdentity();
46         if (ident != newIdent) {
47             Log.wtf(TAG, "Thread identity changed from 0x"
48                     + Long.toHexString(ident) + " to 0x"
49                     + Long.toHexString(newIdent) + " while dispatching to "
50                     + msg.target.getClass().getName() + " "
51                     + msg.callback + " what=" + msg.what);
52         }
53 
54         msg.recycleUnchecked();
55     }
56 }

每个Message被处理完之后,会被自动回收,放回Message池中。

Looper退出

通过调用quit或者quitSafely退出Looper循环。底层是调用MessageQueue的quit函数实现:

 1 void quit(boolean safe) {
 2     if (!mQuitAllowed) {
 3         throw new IllegalStateException("Main thread not allowed to quit.");
 4     }
 5 
 6     synchronized (this) {
 7         if (mQuitting) {
 8             return;
 9         }
10         mQuitting = true;
11 
12         if (safe) {
13             removeAllFutureMessagesLocked();
14         } else {
15             removeAllMessagesLocked();
16         }
17 
18         // We can assume mPtr != 0 because mQuitting was previously false.
19         nativeWake(mPtr);
20     }
21 }

quit调用removeAllMessageLocked,该函数会直接移除MessageQueue中所有尚未处理的Message;quitSafely调用removeAllFutureMessageLocked,该函数只会移除执行时刻晚于当前时刻的Message(即,Message.when > now)。

posted on 2017-10-12 12:06  游不动の鱼  阅读(277)  评论(0编辑  收藏  举报