一、前言

  源码分析使用的版本是 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一起实现延迟消息,我非常感兴趣。

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

  1. Android消息机制源码分析

    本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Me ...

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

    转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium ...

  3. OpenGL—Android 开机动画源码分析一

    .1 Android开机动画实现方式目前实现Android开机动画的方式主要是逐帧动画和OpenGL动画. ?逐帧动画 逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的 ...

  4. Android分包MultiDex源码分析

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/52845661 本文出自: [HansChen的博客] 概述 Android开发者应该 ...

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

    android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...

  6. Handler Looper源码解析(Android消息传递机制)

    Android的Handler类应该是常用到的,多用于线程间的通信,以及子线程发送消息通知UI线程刷新View等等.这里我主要总结下我对整个消息传递机制,包括Handler,Looper,Messag ...

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

    相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.jav ...

  8. 我的Android进阶之旅------>Android中AsyncTask源码分析

    在我的<我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例>文章中,先后使用了Handler和AsyncTask两种方式实现异步任务机制. ...

  9. Android 开机动画源码分析

    Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,如SurfaceFlinger,SensorService等,在第二阶段则启动一系列的J ...

随机推荐

  1. paip.sqlite 管理最好的工具 SQLite Expert 最佳实践总结

    paip.sqlite 管理最好的工具 SQLite Expert 最佳实践总结 一般的管理工具斗可以...就是要是sqlite没正常地关闭哈,有shm跟wal文件..例如ff的place.sqlit ...

  2. Maven学习总结(一)——Maven入门——转载

    一.Maven的基本概念 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服务于基于Java平台的项目构建,依赖管理和项目信息管理. 1.1. ...

  3. ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——菜单模块的实现(二)

    ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——数据库的设计(一) 菜单和模块是在同一个表中,采用的是树形结构,模块菜单表结构如下代码: USE [Permis ...

  4. MySQL分区表

    当数据库数据量涨到一定数量时,性能就成为我们不能不关注的问题,如何优化呢? 常用的方式不外乎那么几种: 1.分表,即把一个很大的表达数据分到几个表中,这样每个表数据都不多. 优点:提高并发量,减小锁的 ...

  5. Scala 深入浅出实战经典 第57讲:Scala中Dependency Injection实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. 【转】drupal7请求异常,执行时间过长的解决方法

    drupal7请求错误,执行时间过长的解决办法 根据你的系统或网络设置Drupal不能读取网页,造成功能缺失.可能是web服务器配置或PHP设置引起的,可用更新.获取更新源.使用OpenID登 录或使 ...

  7. [原创]Java中的字符串比较,按照使用习惯进行比较

    java中的字符串比较一般可以采用compareTo函数,如果a.compareTo(b)返回的是小于0的数,那么说明a的unicode编码值小于b的unicode编码值. 但是很多情况下,我们开发一 ...

  8. VS替换空行

    visual studio2012 改变了正则表达式的写法 因此原来的不管用了 Old: ^:b*$\n New: ^(?([^\r\n])\s)*\r?$\r?\n Click Ctrl-H (qu ...

  9. Kafka - SQL 引擎分享

    1.概述 大多数情况下,我们使用 Kafka 只是作为消息处理.在有些情况下,我们需要多次读取 Kafka 集群中的数据.当然,我们可以通过调用 Kafka 的 API 来完成,但是针对不同的业务需求 ...

  10. ffrpc相关文章列表

    ffrpc 是异步c++通信库.可以说是传统rpc模式和zeromq模式的一个结合,采用broker模式封装client和server之间的拓扑关系,而client和server的通信仍然按照请求应答 ...