可能是出于性能的考虑,Android的UI操作是非线程安全的。

也就是说,如果你在一个新开的线程中直接操作UI是会引发异常的。

但是,Android又规定,不要去阻塞UI线程!否则,轻者引起程序卡顿,重者直接引发臭名昭著的“ANR”异常。

为了解决这一种矛盾,Android引入了Handler来解决这个问题。

Handler有两种常见的用法:

第一种是“发送信息”,我们可以将我们要改变的参数通过Message发送给指定的Handler,然后在Handler中的handleMessage方法中进行处理。

另一种是将一个runnable对象“post”给Handler对象去执行。

实际上,这两种方法是没有太本质的区别的。

接下来从源代码的角度来看Handler的整个运行机制。

首先先来看看Message对象:

message中有几个比较重要的成员变量

what // 一个用来表示这个信息的类型

arg1 // 参数1

arg2 // 参数2

object // 可以携带任何一个对象

还有这一个:

这个东东就是用来传递Runnable对象的。

接下来看Handler的sendMessage方法:

可以看到,它实际上是调用另一个发送的方法,我们跟进去:

靠,原来这几个方法是一回事来的,继续看:

终于不一样了~~~,这里多了一个MessageQueue对象,神马东西?从名字上看应该是“信息队列”的意思。也就是说,实际上,我们发送给Handler的信息并不是直接交给Handler去处理,而是Handler会把Message先放入一个MessageQueue中。MessageQueue就是一个数据结构,以队列的形式管理Message。那么,谁又把Message从Message从MessageQueue中拿出来呢?

这就需要另一个对象Looper了。

Looper的构造方法很有意思:

那也就是说我们是无法直接创建Looper对象的,经验告诉我们,这种情况下,一般不是单例就是工厂。实际上是这个:

这个方法保证了一个线程中只有一个Looper对象,否则会出现异常。

实际上,Looper中有一个loop方法:

上面是我把无关代码去掉后的loop方法,这个方法中looper对象一直去调用MessageQueue的next()方法,也就是不断地从消息队列中取出消息,然后重点来了:

嗯,这一步就是把消息交给对应的Handler去处理。

那么post一个Runnable对象又是怎么做到的呢?

这方法看起来相当的亲切啊!猜应该也可以猜到了getPostMessage方法是怎么实现了吧:

猜对没有?

所以本质上都是通过发信息来实现的。

看看dispatchMessage是怎么做的吧:

接下来就好说了,如果callback不是null,那就是让它去run咯!如果是普通消息, 那就是靠我们自己写的handleMessage去处理了。

至此,Handler的运行机制就是这些了。很喜欢张龙老师的一句话:源代码下,了无秘密。

总结一下:

Message:这个对象携带着我们想做的信息。

MessageQueue:以队列的形式管理Message对象。

Looper:每个线程只有一个Looper对象,它负责管理MessageQueue,会不断地从中取出Message对象,交给相应的Handler去处理。

Handler:它把Message发送给Looper维护的MessageQueue,并负责处理Looper传递过来的Message对象。

by yjiyjige 2013.06.19

Android学习笔记——从源码看Handler的处理机制的更多相关文章

  1. Hadoop学习笔记(9) ——源码初窥

    Hadoop学习笔记(9) ——源码初窥 之前我们把Hadoop算是入了门,下载的源码,写了HelloWorld,简要分析了其编程要点,然后也编了个较复杂的示例.接下来其实就有两条路可走了,一条是继续 ...

  2. [转]OpenTK学习笔记(1)-源码、官网地址

    OpenTK源码下载地址:https://github.com/opentk/opentk OpenTK使用Nuget安装命令:OpenTK:Install-Package OpenTK -Versi ...

  3. 从Chrome源码看浏览器的事件机制

    .aligncenter { clear: both; display: block; margin-left: auto; margin-right: auto } .crayon-line spa ...

  4. Nginx学习笔记4 源码分析

    Nginx学习笔记(四) 源码分析 源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_ ...

  5. Linux简易APR内存池学习笔记(带源码和实例)

    先给个内存池的实现代码,里面带有个应用小例子和画的流程图,方便了解运行原理,代码 GCC 编译可用.可以自己上网下APR源码,参考代码下载链接: http://pan.baidu.com/s/1hq6 ...

  6. Vue2.x源码学习笔记-Vue源码调试

    如果我们不用单文件组件开发,一般直接<script src="dist/vue.js">引入开发版vue.js这种情况下debug也是很方便的,只不过vue.js文件代 ...

  7. Android学习笔记(十四) Handler理论补充

    一.如何下载Android源码 在SDK Manager中选中Sources for Android SDK. 二.ThreadLocal初步介绍 1)执行ThreadLocal对象(static f ...

  8. linux学习笔记-lrmi源码包的编译安装方法

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 官方的lrmi包没有人更新了,如果碰到需要这个编译安装这个包,可以参考我的解决思路,如下: https://pkgs.org/这 ...

  9. MarkDown语法 学习笔记 效果源码对照

    MarkDown基本语法学习笔记 Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. 下面将对Markdown的基本使用做一个介绍 目 ...

随机推荐

  1. io整理

    http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html

  2. Alpha版本总结

    Alpha版本总结 General Questions a)     What went well?  Why? 成功之处:界面设计简洁,功能吸引用户. 原因:铁道大学学生上自习不方便,没有固定的教室 ...

  3. 第一个spring冲刺总结及后诸葛亮报告(附团队贡献分)

    眨眼就完结了第一阶段的冲刺了,之前因为学校停电停水等诸多原因而导致冲刺完毕时间的推迟. 第一阶段总体是做到了运算的功能,只是一些基本的功能实现,但能保证的容错性能较高. 1.在普遍的四则运算中都能见到 ...

  4. 在局域网内部实现远程web终端服务

    在局域网内部实现远程web终端服务 前言 如题,本文主要介绍了在局域网内部实现访问web终端服务功能. 实验环境 如下图所示,实验环境由三个部分组成:分别由局域网内部客户端.重定向服务器.以及两台提供 ...

  5. python项目离线环境配置指南

    参考文献: http://blog.csdn.net/candcplusplus/article/details/52156324 https://www.cnblogs.com/michael-xi ...

  6. CentOS 简单学习 firewalld的使用

    1. centos7 开始 使用firewalld 代替了 iptables 命令工具为 firewall-cmd 帮助信息非常长,简单放到文末 2. 简单使用 首先开启 httpd 一般都自带安装了 ...

  7. Helm 安装 wordpress

    1. 前置需要安装 storageclass 然后 安装helm 客户端 helm tiller 服务端 2. 设置 当前的位阿里云的 repo 3. 查找 wordpress的镜像 helm sea ...

  8. 小程序开发 js里面array操作的方法列表。

  9. 2007-10的PWX OracleCdc问题解答

    1. 捕获增量的底层机制是什么?(例如日志.触发器.LogMiner) PWX利用Oracle的LogMiner来提取来自于Oracle的增量, LogMiner是由Oracle数据库提供的,如果当前 ...

  10. MT【197】存在$a,b$对于任意的$x$

    已知$f(x)=ax^2+bx-\dfrac{1}{4}$,若存在$a,b\in R$,使得对于任意的$x\in[0,7],|f(x)|\le2$恒成立,求$|a|$的最大值____ 提示:$|ax^ ...