【Android】Handler、Looper源码分析
一、前言
源码分析使用的版本是 4.4.2_r1。
Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制
简单而言:Handler和Looper是对某一个线程实现消息机制的重要组成部分,另外两个重要元素是Message和MessageQueue,通过这四个类,可以让某个线程具备接收、处理消息的能力。
二、源码剖析
虽然只有四个类,而且这里只是剖析其中两个,但是也不能独立分析,必须组合进行解析。切入点是类Looper的注释中的一段示例代码:
1 class LooperThread extends Thread { 2 public Handler mHandler; 3 4 public void run() { 5 Looper.prepare(); 6 7 mHandler = new Handler() { 8 public void handleMessage(Message msg) { 9 // process incoming messages here 10 } 11 }; 12 Looper.loop(); 13 } 14 }
这段代码描述了如何将一个普通的线程转变为一个Looper线程,即让它具备消息的循环处理能力。我们从Looper入手,看看这里到底做了什么。
代码一:
1 /** Initialize the current thread as a looper. 2 * This gives you a chance to create handlers that then reference 3 * this looper, before actually starting the loop. Be sure to call 4 * {@link #loop()} after calling this method, and end it by calling 5 * {@link #quit()}. 6 */ 7 public static void prepare() { 8 prepare(true); 9 } 10 11 private static void prepare(boolean quitAllowed) { 12 if (sThreadLocal.get() != null) { 13 throw new RuntimeException("Only one Looper may be created per thread"); 14 } 15 sThreadLocal.set(new Looper(quitAllowed)); 16 }
这里展示的是Looper的静态方法,即prepare(),前面代码中第5行调用。
第13行可以看到一个运行时异常,其打印信息翻译为:每一个线程只允许拥有一个Looper,而且判断条件中用到ThreadLocal对象,如果不明白这是什么,可以参考我的另外一篇博客:深入理解ThreadLocal。总之,第一次调换用这个方法并且之前没有调用过,则会调用第15行的代码,这里实例化了一个Looper对象,其构造方法如下:
代码二:
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mThread = Thread.currentThread(); 4 }
第2行初始化了一个MessageQueue,顾名思义,就是为Looper创建绑定了一个消息队列。
第3行则获取当前线程,即调用Looper的线程。这样即可将Looper绑定到一个线程上,同时为一个线程创建一个消息队列。
在消息机制里面,Looper只是负责管理消息队列,也就是取出消息进行处理,而Handler则是负责发送消息以及处理消息的,那么Handler和Looper又是如何绑定到一起的呢?看切入点里面的7-11行,这里做了什么呢?下面的分析涉及到Looper中的几个方法,这里插入分析一下:
代码三:
1 /** 2 * Return the Looper object associated with the current thread. Returns 3 * null if the calling thread is not associated with a Looper. 4 */ 5 public static Looper myLooper() { 6 return sThreadLocal.get(); 7 } 8 9 /** Returns the application‘s main looper, which lives in the main thread of the application. 10 */ 11 public static Looper getMainLooper() { 12 synchronized (Looper.class) { 13 return sMainLooper; 14 } 15 }
很明显可以看到myLooper是获取属于当前线程的Looper,而getMainLooper则是获取应用的主Looper,它由属性sMainLooper引用,其赋值过程如下。
代码四:
1 /** 2 * Initialize the current thread as a looper, marking it as an 3 * application‘s main looper. The main looper for your application 4 * is created by the Android environment, so you should never need 5 * to call this function yourself. See also: {@link #prepare()} 6 */ 7 public static void prepareMainLooper() { 8 prepare(false); 9 synchronized (Looper.class) { 10 if (sMainLooper != null) { 11 throw new IllegalStateException("The main Looper has already been prepared."); 12 } 13 sMainLooper = myLooper(); 14 } 15 }
注释中说到,这个方法不应该由程序员自己调用,我猜测这个方法应该是在应用启动的时候,由属于应用的第一个线程调用,之后如果再次调用,就会抛出异常了,因为sMainLooper实际上是一个static变量,也就是说它是属于整个应用的。
准备完毕,现在回到主题,
代码五:
1 /** 2 * Default constructor associates this handler with the {@link Looper} for the 3 * current thread. 4 * 5 * If this thread does not have a looper, this handler won‘t be able to receive messages 6 * so an exception is thrown. 7 */ 8 public Handler() { 9 this(null, false); 10 } 11 /** 12 * Use the {@link Looper} for the current thread with the specified callback interface 13 * and set whether the handler should be asynchronous. 14 * 15 * Handlers are synchronous by default unless this constructor is used to make 16 * one that is strictly asynchronous. 17 * 18 * Asynchronous messages represent interrupts or events that do not require global ordering 19 * with represent to synchronous messages. Asynchronous messages are not subject to 20 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 21 * 22 * @param callback The callback interface in which to handle messages, or null. 23 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 24 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 25 * 26 * @hide 27 */ 28 public Handler(Callback callback, boolean async) { 29 if (FIND_POTENTIAL_LEAKS) { 30 final Class<? extends Handler> klass = getClass(); 31 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 32 (klass.getModifiers() & Modifier.STATIC) == 0) { 33 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 34 klass.getCanonicalName()); 35 } 36 } 37 38 mLooper = Looper.myLooper(); 39 if (mLooper == null) { 40 throw new RuntimeException( 41 "Can‘t create handler inside thread that has not called Looper.prepare()"); 42 } 43 mQueue = mLooper.mQueue; 44 mCallback = callback; 45 mAsynchronous = async; 46 }
重点在于39-43行。第38行调用myLooper()方法获取属于本线程的Looper,如果你在这之前没有调用Looper.prepare()方法,则会返回null,此时就会抛出异常,要求你在这之前调用Looper.prepare()方法。而平时我们在主线程中使用Handler的时候,并不需要调用Looper.prepare()方法,这是因为主线程默认绑定一个Looper。
接下去43行则是获取Looper的消息队列。
除了这种简单的创建方式之外,Handler也还有别的创建方式,比如:
代码六:
1 /** 2 * Use the provided {@link Looper} instead of the default one and take a callback 3 * interface in which to handle messages. Also set whether the handler 4 * should be asynchronous. 5 * 6 * Handlers are synchronous by default unless this constructor is used to make 7 * one that is strictly asynchronous. 8 * 9 * Asynchronous messages represent interrupts or events that do not require global ordering 10 * with represent to synchronous messages. Asynchronous messages are not subject to 11 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 12 * 13 * @param looper The looper, must not be null. 14 * @param callback The callback interface in which to handle messages, or null. 15 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 16 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 17 * 18 * @hide 19 */ 20 public Handler(Looper looper, Callback callback, boolean async) { 21 mLooper = looper; 22 mQueue = looper.mQueue; 23 mCallback = callback; 24 mAsynchronous = async; 25 }
这里传入了一个Looper,而mLooper的赋值不是获取当前线程的Looper,而是直接取用该looper,这引起一个怀疑:一个Looper(或者说一个线程,因为是线程和Looper是一一对应的关系)可以绑定不止一个Handler,因为很明显我可以用一个Looper通过上述构造方法传入到不同的Handler中去,那么自然而然又想到一个问题:Handler是用于发送和处理消息的,那么当一个Looper绑定多个Handler的时候,发送来的消息肯定都是存储在Looper的消息队列中的,那么处理消息的时候,是怎么处理的呢?每一个Handler都处理一遍么?继续看源码,首先看发送消息的函数:
代码七:
1 public final boolean sendMessage(Message msg) 2 { 3 return sendMessageDelayed(msg, 0); 4 } 5 6 public final boolean sendEmptyMessage(int what) 7 { 8 return sendEmptyMessageDelayed(what, 0); 9 } 10 11 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 12 Message msg = Message.obtain(); 13 msg.what = what; 14 return sendMessageDelayed(msg, delayMillis); 15 } 16 17 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { 18 Message msg = Message.obtain(); 19 msg.what = what; 20 return sendMessageAtTime(msg, uptimeMillis); 21 } 22 23 public final boolean sendMessageDelayed(Message msg, long delayMillis) 24 { 25 if (delayMillis < 0) { 26 delayMillis = 0; 27 } 28 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 29 } 30 31 /** 32 * Enqueue a message into the message queue after all pending messages 33 * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 34 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 35 * You will receive it in {@link #handleMessage}, in the thread attached 36 * to this handler. 37 * 38 * @param uptimeMillis The absolute time at which the message should be 39 * delivered, using the 40 * {@link android.os.SystemClock#uptimeMillis} time-base. 41 * 42 * @return Returns true if the message was successfully placed in to the 43 * message queue. Returns false on failure, usually because the 44 * looper processing the message queue is exiting. Note that a 45 * result of true does not mean the message will be processed -- if 46 * the looper is quit before the delivery time of the message 47 * occurs then the message will be dropped. 48 */ 49 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 50 MessageQueue queue = mQueue; 51 if (queue == null) { 52 RuntimeException e = new RuntimeException( 53 this + " sendMessageAtTime() called with no mQueue"); 54 Log.w("Looper", e.getMessage(), e); 55 return false; 56 } 57 return enqueueMessage(queue, msg, uptimeMillis); 58 }
为了清晰,前面的方法全部都去掉了注释,只剩下最后一个方法,我们看到,往消息队列中添加消息,最后调用的是方法enqueueMessage。其实现如下:
代码八:
1 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 2 msg.target = this; 3 if (mAsynchronous) { 4 msg.setAsynchronous(true); 5 } 6 return queue.enqueueMessage(msg, uptimeMillis); 7 }
方法的最后调用了MessageQueue的enqueueMessage方法,从上面的流程可以看到,queue其实就是从mLooper中取出的MessgaeQueue。最终到了这里,消息可以通过Handler顺利压入绑定的Looper中的MessageQueue中去了。接下去就是消息的处理。这里需回到Looper中去,因为循环取出消息进行处理是Looper的工作。
前面切入点代码中可以看到,在调用Looper.prepare()方法,实例化Handler之后,还有一个方法需要调用,即Looper.loop()方法。
代码九:
1 /** 2 * Run the message queue in this thread. Be sure to call 3 * {@link #quit()} to end the loop. 4 */ 5 public static void loop() { 6 final Looper me = myLooper(); 7 if (me == null) { 8 throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); 9 } 10 final MessageQueue queue = me.mQueue; 11 12 // Make sure the identity of this thread is that of the local process, 13 // and keep track of what that identity token actually is. 14 Binder.clearCallingIdentity(); 15 final long ident = Binder.clearCallingIdentity(); 16 17 for (;;) { 18 Message msg = queue.next(); // might block 19 if (msg == null) { 20 // No message indicates that the message queue is quitting. 21 return; 22 } 23 24 // This must be in a local variable, in case a UI event sets the logger 25 Printer logging = me.mLogging; 26 if (logging != null) { 27 logging.println(">>>>> Dispatching to " + msg.target + " " + 28 msg.callback + ": " + msg.what); 29 } 30 31 msg.target.dispatchMessage(msg); 32 33 if (logging != null) { 34 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 35 } 36 37 // Make sure that during the course of dispatching the 38 // identity of the thread wasn‘t corrupted. 39 final long newIdent = Binder.clearCallingIdentity(); 40 if (ident != newIdent) { 41 Log.wtf(TAG, "Thread identity changed from 0x" 42 + Long.toHexString(ident) + " to 0x" 43 + Long.toHexString(newIdent) + " while dispatching to " 44 + msg.target.getClass().getName() + " " 45 + msg.callback + " what=" + msg.what); 46 } 47 48 msg.recycle(); 49 } 50 }
前面6-16行就不多解释了,关键看17行,这里是一个死循环,无限循环表示从队列中获取消息;第18行也很关键,这里调用MessageQueue的next方法获取下一个消息,很重要的地方在于注释:might block。可能会阻塞!如果不注意这一点,很可能就会误认为调用该方法,因为当时队列中还没有消息,所以就会执行第21行,直接返回了,而看到这个注释,再加上第20-22行的代码,我们容易猜测,MessageQueue通过在next()方法中返回null来表示整个队列的取消,从而终结消息机制,OK,不多说,言归正传,这一段代码最重要的是看31行:msg.target.dispatchMessage(msg);这行代码预示着如何处理消息!
每一个Message都有一个target属性,该属性的声明如下:
1 /*package*/ Handler target;
没错,是Handler类型!反观代码,在代码八的第2行,有一行很重要的代码被忽视了:
1 msg.target = this;
在Handler发送没一个消息进入队列之前,都会将其target设置为自己。从这里就可以看到之前那个问题(红色部分)的答案,消息是交给发送它的Handler处理的!接下来自然要去看的是Handler的dispatchMessage方法:
1 /** 2 * Handle system messages here. 3 */ 4 public void dispatchMessage(Message msg) { 5 if (msg.callback != null) { 6 handleCallback(msg); 7 } else { 8 if (mCallback != null) { 9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }
注释即说明它是处理消息的,在这里可以进行一些回调,这里不说明。主要看第13行,调用了handleMessage()方法,其实现如下:
代码十一:
1 /** 2 * Subclasses must implement this to receive messages. 3 */ 4 public void handleMessage(Message msg) { 5 }
终于到这一步了!注释中就能看到,我们在实例化Handler的子类的时候,是需要重载这个方法的,否则你的消息不会得到处理,实现参见切入点8-11行!具体使用可以参见我的博客Android Handler机制。
三、总结
源码剖析中,主要关注的对象是:Thread,Handler,Looper三个重量级对象是如何绑定到一起的,以及消息是如何在Handler和Looper中存在和传播的,从源码中看这个过程非常清楚。其实整个设计并没有什么新奇的技巧,但是设计非常合理,值得借鉴。
下一篇博客会去探索一下MessageQueue,关于MessageQueue如何管理消息,和Looper一起实现延迟消息,我非常感兴趣。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。