Handler Looper源码解析(Android消息传递机制)
Android的Handler类应该是常用到的,多用于线程间的通信,以及子线程发送消息通知UI线程刷新View等等。这里我主要总结下我对整个消息传递机制,包括Handler,Looper,Message,MessageQueue类的理解。
Looper类:每一个线程都只能拥有一个Looper对象,这里Android是通过将Looper对象设置为当前线程的线程局部变量(这里涉及到ThreadLocal类),可以通过调用Looper.prepare()方法来使当前线程拥有一个Looper对象(主线程不用调用,因为主线程本身已经是拥有Looper对象了)。这里贴出prepare()的源码
- public static void prepare() {
- prepare(true);
- }
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread"); /*如果当前线程已经拥有Looper对象,就会报错。*/
- }
- sThreadLocal.set(new Looper(quitAllowed));/*新建Looper对象并设置为当前线程的线程局部变量。*/
- }
而Looper类的主要作用是进行消息循环,Looper类维护了一个MesageQueue,通过不停调用loop()方法来取出MeesageQueue中的Message并进行相应的处理。
- public static void loop() {
- final Looper me = myLooper(); /*得到当前线程的Looper对象*/
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }/*如果为空 报异常*/
- final MessageQueue queue = me.mQueue;
- // Make sure the identity of this thread is that of the local process,
- // and keep track of what that identity token actually is.
- Binder.clearCallingIdentity();
- final long ident = Binder.clearCallingIdentity();
- /* 进行消息循环 */
- for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
- return;
- }
- // This must be in a local variable, in case a UI event sets the logger
- Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- msg.target.dispatchMessage(msg);
- if (logging != null) {
- logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
- }
- // Make sure that during the course of dispatching the
- // identity of the thread wasn't corrupted.
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf(TAG, "Thread identity changed from 0x"
- + Long.toHexString(ident) + " to 0x"
- + Long.toHexString(newIdent) + " while dispatching to "
- + msg.target.getClass().getName() + " "
- + msg.callback + " what=" + msg.what);
- }
- msg.recycle();/* 回收msg(重复利用Message对象) */
- }
- }
这个留意到loop()方法里对Message的处理方式是调用msg.target.dispatchMessage(msg);,关于这个方法,我们了解完Handler后再看。
MeesageQueue:Message队列,队列就不详解了,先进先出。
Handler:Handler的作用主要是分发信息 相关方法有:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- }
- public final boolean sendEmptyMessage(int what)
- {
- return sendEmptyMessageDelayed(what, 0);
- }
- public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
- Message msg = Message.obtain();
- msg.what = what;
- return sendMessageDelayed(msg, delayMillis);
- }
- public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
- Message msg = Message.obtain();
- msg.what = what;
- return sendMessageAtTime(msg, uptimeMillis);
- }
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- MessageQueue queue = mQueue;
- if (queue == null) {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- return false;
- }
- return enqueueMessage(queue, msg, uptimeMillis);
- }
发现这些方法最后都是调用enqueueMessage(),看看这个方法的源码
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
调用了MessageQueue的enqueueMessage方法,将Message对象加入了队列中去
再看看这几个方法
- public final boolean post(Runnable r)
- {
- return sendMessageDelayed(getPostMessage(r), 0);
- }
- public final boolean postAtTime(Runnable r, long uptimeMillis)
- {
- return sendMessageAtTime(getPostMessage(r), uptimeMillis);
- }
- public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
- {
- return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
- }
- public final boolean postDelayed(Runnable r, long delayMillis)
- {
- return sendMessageDelayed(getPostMessage(r), delayMillis);
- }
发现post()系列的方法最后都是调用sendMessage系列的方法只是传入的Message对象有所不同,我们再看看getPostMessage()
- private static Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;
- }
- private static Message getPostMessage(Runnable r, Object token) {
- Message m = Message.obtain();
- m.obj = token;
- m.callback = r;
- return m;
- }
发现其实就是把Runnable对象赋给Message的callback。通过以上代码的分析,基本上对整个消息机制有个概念了,当我们调用Handler的sendMessage()或post()等一系列方法时,Handler会将消息加入到MessageQueue中,这个MessageQueue为Handler对应的Looper对象所维护的queue(创建Handler时可以传入Looper对象,无参情况下为当前线程的Looper,想具体了解可以看下Handler的构造函数,这里不再赘述)然后由Looper类的loop()方法将消息取出。并做处理。至于怎么处理,我们就要看下msg.target.dispatchMessage(msg)这个方法了。我们知道msg的target是一个Handler对象,看下这个方法的源码
- public void dispatchMessage(Message msg) {
- /* 如果callback不为空,即发送消息的时候传入了Runnable对象,也就是调用的是post()系列的方法。那么就会执行handleCallback()这个方法,否则执行handleMessage() */
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
handleMessge()方法想必大家都很熟悉,这个方法是我们new一个Handler对象时常常会去重写的,然后处理消息时会回调这个方法。再看看handleCallback()
- private static void handleCallback(Message message) {
- message.callback.run();
- }
代码很简单,就是调用了callback的run()方法。这里要特别注意的是调用的是run()而不是start(),这意味着将不会另起一个线程。而是在Looper对象所在的线程执行。至于为什么这么做笔者认为由于这样做即使是多次post也不需要开启多个线程,大大提高了程序的性能,同时,在某些情况下,我们希望能够顺序执行callback,那么使用这个方法无疑是非常棒的。当然,如果是要并发执行作那么就得使用其他法子了。总的来说post()方法相当于sendMessage()+handleMessage()使用方式的一种变体。
Handler Looper源码解析(Android消息传递机制)的更多相关文章
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)
不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...
- 源码解析Android中View的measure量算过程
Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View ...
- Netty源码解析 -- 事件循环机制实现原理
本文主要分享Netty中事件循环机制的实现. 源码分析基于Netty 4.1 EventLoop 前面分享服务端和客户端启动过程的文章中说过,Netty通过事件循环机制(EventLoop)处理IO事 ...
- Netty源码解析 -- 零拷贝机制与ByteBuf
本文来分享Netty中的零拷贝机制以及内存缓冲区ByteBuf的实现. 源码分析基于Netty 4.1.52 Netty中的零拷贝 Netty中零拷贝机制主要有以下几种 1.文件传输类DefaultF ...
- Android Handler机制(四)---Handler源码解析
Handler的主要用途有两个:(1).在将来的某个时刻执行消息或一个runnable,(2)把消息发送到消息队列. 主要依靠post(Runnable).postAtTime(Runnable, l ...
- Android 进阶16:IntentService 使用及源码解析
It's time to start living the life you've only imagined. 读完本文你将了解: IntentService 简介 IntentService 源码 ...
- Android 开源项目源码解析(第二期)
Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...
- Android 进阶15:HandlerThread 使用场景及源码解析
眼睛困得要死,但今天的计划不完成又怎么能睡呢?明日复明日,明日何其多啊! 读完本文你将了解: HandlerThread 简介 HandlerThread 源码 HandlerThread 的使用场景 ...
随机推荐
- linux中常用的命令大全
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...
- python+tushare获取上市公司财务报表:资产负债表
接口:balancesheet 描述:获取上市公司资产负债表 积分:用户需要至少500积分才可以调取,具体请参阅本文最下方积分获取办法 注:tushare包下载和初始化教程,请查阅我之前的文章 提示: ...
- Spring mvc的执行流程
一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理 DispatcherSe ...
- 解决虚拟机克隆的linux系统ip无法正常使用问题
当我们克隆centos虚拟机无法正常获取IP地址,重启网卡也提示Bringing up interface eth0: Device eth0 does not seem to be present ...
- Codeforces 19E&BZOJ 4424 Fairy(好题)
日常自闭(菜鸡qaq).不过开心的是看了题解之后1A了.感觉这道题非常好,必须记录一下,一方面理清下思路,一方面感觉自己还没有完全领会到这道题的精髓先记下来以后回想. 题意:给定 n 个点,m 条边的 ...
- informix 计算 日期之差
原文地址:http://blog.chinaunix.net/uid-678894-id-3138829.html https://blog.csdn.net/zhengqiqiqinqin/arti ...
- C#接口的作用实例解析
一.接口的作用: 我们定义一个接口: public interface IBark { void Bark(); } 1. 再定义一个类,继承于IBark,并且必需实现其中的Bark()方法 pub ...
- Java Number&Math类
Java Number类 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double等. 实例 int i = 5000; float gpa = 13.65 ...
- Yii2数据库操作 事务
Yii2 DAO http://blog.csdn.net/hzqghost/article/details/44116039
- sql 修改数据
关系数据库的基本操作就是增删改查,即CRUD:Create.Retrieve.Update.Delete.其中,对于查询,我们已经详细讲述了SELECT语句的详细用法. 而对于增.删.改,对应的SQL ...