【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一起实现延迟消息,我非常感兴趣。

时间: 2024-10-25 10:48:01

【Android】Handler、Looper源码分析的相关文章

Android -- 消息处理机制源码分析(Looper,Handler,Message)

android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类.下面一一介绍: Looper Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线程.在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Lo

Android 开源项目源码分析第一期正式发布

由 Trinea 发起.几十名 Android 开发者参与的Android 开源项目源码分析第一期正式发布. 从简介.总体设计.流程图.详细设计全方面分析开源库源码,第一期包括 10 个著名开源库及 5 个公共技术点的全面介绍. 分析文档 作者 Volley 源码解析 grumoon Universal Image Loader 源码分析 huxian99 Dagger 源码解析 扔物线 EventBus 源码解析 Trinea xUtils 源码解析 Caij ViewPagerindicat

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

子墨庖丁Android的ActionBar源码分析 (一)实例化

如果你从事过Android客户端开发,相信你对ActionBar这套框架并不陌生,或者说你并不了解它,但是你应该时不时的要跟它打交道.抛开ActionBar的实现不说,ActionBar实际上是对Android的TitleBar行为的抽象,这种框架可以适用于这种模式的应用,是对需要的行为视图的抽象.当然或许你也和我一样,对ActionBar的实现效率并不满意,因为你打开它的视图,你会发现它的实现非常的ugly.不过我们庆幸的看到的是,ActionBar在设计的时候就并不是以一个强类型的姿态存在,

Handler机制.源码分析

Handler机制的原理 : Android提供了handler 和 looper 来满足线程之间的通信 Handler是先进先出的原则 一个线程可以产生一个looper对象,由它去管理线程里面消息队列 MessageQueue Handler 你可以构造handler对象来与looper沟通.可以发送消息 和处理消息 MessageQueue 用来存放线程放入的消息 线程 一般值的是主线程 UIthread Android启动程序的时候会替他建立一个MessageQueue   .Handle

Android消息机制源码分析

本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Message)插入到当前线程的消息队列,并负责分发Looper中的消息,将消息发送到当前线程执行 具体关系图如下所示: 接下来我们来分析一下Looper和Handler的源码,了解一下其中的奥妙. 首先我们从一个程序运行的入口来分析,源码如下: public static void main(Stri

Android网络框架源码分析一---Volley

转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium=mobile_author_hots&utm_source=recommendation 公司最近新起了一个项目,对喜欢尝鲜的我们来说,好处就是我们可以在真实的项目中想尝试一些新技术,验证想法.新项目对网络框架的选取,我们存在三种方案: 1.和我们之前的项目一样,使用Loader + HttpCli

Android分包MultiDex源码分析

概述 Android开发者应该都遇到了64K最大方法数限制的问题,针对这个问题,google也推出了multidex分包机制,在生成apk的时候,把整个应用拆成n个dex包(classes.dex.classes2.dex.classes3.dex),每个dex不超过64k个方法.使用multidex,在5.0以前的系统,应用安装时只安装main dex(包含了应用启动需要的必要class),在应用启动之后,需在Application的attachBaseContext中调用MultiDex.i

[Android]简略的Android消息机制源码分析

相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.java framework/base/core/java/andorid/os/Message.java framework/base/core/java/andorid/os/MessageQueue.java libcore/luni/src/main/java/java/lang/ThreadLo