Android学习笔记——从源码看Handler的处理机制
可能是出于性能的考虑,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的处理机制的更多相关文章
- Hadoop学习笔记(9) ——源码初窥
Hadoop学习笔记(9) ——源码初窥 之前我们把Hadoop算是入了门,下载的源码,写了HelloWorld,简要分析了其编程要点,然后也编了个较复杂的示例.接下来其实就有两条路可走了,一条是继续 ...
- [转]OpenTK学习笔记(1)-源码、官网地址
OpenTK源码下载地址:https://github.com/opentk/opentk OpenTK使用Nuget安装命令:OpenTK:Install-Package OpenTK -Versi ...
- 从Chrome源码看浏览器的事件机制
.aligncenter { clear: both; display: block; margin-left: auto; margin-right: auto } .crayon-line spa ...
- Nginx学习笔记4 源码分析
Nginx学习笔记(四) 源码分析 源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_ ...
- Linux简易APR内存池学习笔记(带源码和实例)
先给个内存池的实现代码,里面带有个应用小例子和画的流程图,方便了解运行原理,代码 GCC 编译可用.可以自己上网下APR源码,参考代码下载链接: http://pan.baidu.com/s/1hq6 ...
- Vue2.x源码学习笔记-Vue源码调试
如果我们不用单文件组件开发,一般直接<script src="dist/vue.js">引入开发版vue.js这种情况下debug也是很方便的,只不过vue.js文件代 ...
- Android学习笔记(十四) Handler理论补充
一.如何下载Android源码 在SDK Manager中选中Sources for Android SDK. 二.ThreadLocal初步介绍 1)执行ThreadLocal对象(static f ...
- linux学习笔记-lrmi源码包的编译安装方法
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 官方的lrmi包没有人更新了,如果碰到需要这个编译安装这个包,可以参考我的解决思路,如下: https://pkgs.org/这 ...
- MarkDown语法 学习笔记 效果源码对照
MarkDown基本语法学习笔记 Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. 下面将对Markdown的基本使用做一个介绍 目 ...
随机推荐
- Unity插件-NGUI学习笔记
Anchors 的作用 类似Android里面的.9格式图片的功能, 边框可以随着文字变大而变大. 实现方法: 用NGUI 创建一个Sprite, 命名为TextBg, 一个Label, Label的 ...
- 全局最小割StoerWagner算法详解
前言 StoerWagner算法是一个找出无向图全局最小割的算法,本文需要读者有一定的图论基础. 本文大部分内容与词汇来自参考文献(英文,需***),用兴趣的可以去读一下文献. 概念 无向图的割:有无 ...
- Day Three
站立式会议 站立式会议内容总结 442 今天:从本地导入电子书页面编写以及部分逻辑代码 遇到的问题:界面适配问题 明天:具体计划界面的编写,解决上面问题 331 今天:监听webview滑动底端事件 ...
- Practice1小学四则运算(改进)
#include<stdio.h> #include<stdlib.h> #include<time.h> void srand(unsigned);//随机生成不 ...
- Ns3 构建哑铃型拓扑,并实现两个点的TCP连接(详细请戳全文)
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAaUAAADlCAIAAAB8n38hAAAV8UlEQVR4nO3dMWjjyBoH8CkNj1uc5v
- Cloudstack 的搭建
Note: 关闭了NFS Storage 的防火墙 service iptables stop 1. 新创建的Linux没有获取IP; vi /etc/sysconfig/network-script ...
- css实现table中td单元格鼠标悬浮时显示更多内容
table中,td单元格无法显示下全部内容,需要在鼠标hover时显示全部内容. 正常显示样式: 鼠标hover时: html: <td>displayAddress<span cl ...
- c# 新建文本文件、遍历读取文本、删除文本行
如果该物理路径没有该文本则创建一个新文本 if (!File.Exists(@"C:\db.txt")){FileStream fs = new FileStream(@" ...
- 洛谷U19464 山村游历(Wander)(LCT)
洛谷题目传送门 LCT维护子树信息常见套路详见我的总结 闲话 题目摘自WC模拟试题(by Philipsweng),原题目名Wander,"山村游历"是自己搞出来的中文名. 数据自 ...
- 【Revit API】创建共享参数
话不多说,直接上代码 var app = doc.Application; app.SharedParametersFilename = sharedParamFilePath; Definition ...