书史足自悦,安用勤与劬。这篇文章主要讲述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() { 2final Looper me = myLooper(); 3if (me == null) { 4throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); 5} 6final 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. 10Binder.clearCallingIdentity(); 11final long ident = Binder.clearCallingIdentity(); 12 13for (; ; ) { 14Message msg = queue.next(); // might block 15if (msg == null) { 16// No message indicates that the message queue is quitting. 17return; 18} 19 20// This must be in a local variable, in case a UI event sets the logger 21final Printer logging = me.mLogging; 22if (logging != null) { 23logging.println("> > > > > Dispatching to " + msg.target + " " + 24msg.callback + ": " + msg.what); 25} 26 27final long traceTag = me.mTraceTag; 28if (traceTag != 0 & & Trace.isTagEnabled(traceTag)) { 29Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); 30} 31try { 32msg.target.dispatchMessage(msg); 33} finally { 34if (traceTag != 0) { 35Trace.traceEnd(traceTag); 36} 37} 38 39if (logging != null) { 40logging.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. 45final long newIdent = Binder.clearCallingIdentity(); 46if (ident != newIdent) { 47Log.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 54msg.recycleUnchecked(); 55} 56 }
【Android源码学习 Handler之Looper】每个Message被处理完之后,会被自动回收,放回Message池中。
Looper退出
通过调用quit或者quitSafely退出Looper循环。底层是调用MessageQueue的quit函数实现:
1 void quit(boolean safe) { 2if (!mQuitAllowed) { 3throw new IllegalStateException("Main thread not allowed to quit."); 4} 5 6synchronized (this) { 7if (mQuitting) { 8return; 9} 10mQuitting = true; 11 12if (safe) { 13removeAllFutureMessagesLocked(); 14} else { 15removeAllMessagesLocked(); 16} 17 18// We can assume mPtr != 0 because mQuitting was previously false. 19nativeWake(mPtr); 20} 21 }
quit调用removeAllMessageLocked,该函数会直接移除MessageQueue中所有尚未处理的Message;quitSafely调用removeAllFutureMessageLocked,该函数只会移除执行时刻晚于当前时刻的Message(即,Message.when > now)。
推荐阅读
- Win10更改hosts图文步骤
- 使用AndroidStudio导入github项目
- Mac androidStudio cannot resolve corresponding JNI function
- remount issue on android 7.0
- Android RxVolley = Volley + RxJava + OkHttp
- Web App 分层架构(基于 Vue+Router+Vuex)
- spring配置文件ApplicationContext.xml里面class等没有提示功能
- AndroidStudio2.2 cMake方式创建jni工程
- Android签名机制---签名过程