Android源码学习 Handler之Looper
Posted 荆棘鸟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码学习 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)。
以上是关于Android源码学习 Handler之Looper的主要内容,如果未能解决你的问题,请参考以下文章
Android源码学习 Handler之ThreadLocal
Android :安卓学习笔记之 Handler机制 的简单理解和使用
Android Handler消息机制02-Looper源码学习