之前一直只知道handler如何使用,不知道其中的工作原理,趁着新版本提测阶段比较空闲,及时做一个总结。

先看一下Google官方文档关于handler的解释:

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

巴拉巴拉一大堆,还好没有什么生僻词大概还能看懂个意思,大概意思就是:handler类允许你发送消息和处理线程消息队列中的消息及runnable对象。handler实例都是与一个线程和该线程的消息队列一起使用,一旦创建了一个新的handler实例,系统就把该实例与一个线程和该线程的消息队列捆绑起来,这将可以发送消息和runnable对象给该消息队列,并在消息队列出口处处理它们。

handler类有两种主要用途:1、按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。 2、把一个对另外线程对象的操作请求放入消息队列中,从而避免线程间冲突。

第一个就是执行一个定时任务(可以立刻执行,比如子线程刷新ui),第二个就是异步消息处理机制。

将通俗一点就是1.更新ui   2.实现消息的异步处理


Part1.更新ui:

有的时候在我们需要执行一些耗时的操作,然后执行完了给一个反馈,如上代码开启了一个子线程去下载lol,然后下载完成后提示下载完成,当程序执行到L:64的是后程序崩溃了,报错原因是只有在主线程才能修改视图,L:65-L:70就是一种handler的典型用法,在子线程post出一个runnable对象,还有其他的方式,比如通过sendMsessage(其实post的内部也是实现sendmessage,ps:message的获取方式Android推荐Message.obtain而不是直接new),L:77和L:79是一种消息不带数据的和一种消息带数据的传递,看一下最终的打印信息:

可以看出uiHandler 接收信息处理信息的threadId和主线程的threadId是一样的,因为handler是在主线程中创建的(L:37),所以uiHandler会把消息传递到主线程,然后再主线程进行最终的ui刷新。不过消息是怎么传递处理的呢?说到handler的消息处理,就不得不提Looper、MessageQueue、Handler、Thread这四者之间的关系了,先上一张网上盗的图:

Thread是最基础的,Looper和MessageQueue都构建在Thread之上,Handler又构建在Looper和MessageQueue之上,我们通过Handler间接地与下面这几个相对底层一点的类打交道。

MessageQueue

讲messageQueue之前插播一下message

Message:包含描述和任意数据对象的消息,用于发送给Handler。

message对象很简单,两个int型的数据类型arg1和arg2是msg可以携带的简单数据,what代表msg的消息码,可以理解成让handler接收时明白你是哪一条消息,obj是Object类型的数据,值得注意的是当你arg0和arg1可以满足msg的内容的时候建议使用arg0和arg1,效率要比使用obj对象来的高的多。

MessageQueue:消息队列。内部存储着一组消息。对外提供了插入和删除的操作。MessageQueue内部是以单链表的数据结构来存储消息列表的。

每一个线程内部都维护了一个消息队列,在某一时刻我们点击了ui界面上的某一个按钮,然后有恰巧收到了程序的广播事件,这个时候该如何处理这两个事件呢?因为同一时刻只能处理意见事情,所以Android把点击按钮封装成了一个message,放到messagequeue里面,收到广播也封装成一个message,放到messagequeue,俗称入栈到消息队列,messageQueue就是一堆消息的消息池,线程Thread会一次从消息队列中取出消息进行处理。message按照“先进先出”的原则存放消息,存放并非实际意义的保存,而是将Message对象以链表的方式串联起来的。MessageQueue对象不需要我们自己创建,而是有Looper对象对其进行管理,一个线程最多只可以拥有一个MessageQueue。

Looper

Looper又称消息泵,主要作用是与当前线程创建一个绑定关系,同时创建一个messageQueue,默认情况下开启一个新的线程是不会开启消息循环的(主线程除外),而在子线程中如果想要new Handler()的话需要先调用Looper.prepare(),然后通过Looper.loop()让Looper开始工作,从消息队列里面取消息,将消息发送给对应的处理者(handler),让messageQueue中的消息循环起来。

Handler消息处理机制详解的更多相关文章

  1. 【转载】Android异步消息处理机制详解及源码分析

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  2. Android应用AsyncTask处理机制详解及源码分析

    1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机 ...

  3. 【转载】Android应用AsyncTask处理机制详解及源码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个 ...

  4. ThreadPoolExecutor运转机制详解

    ThreadPoolExecutor运转机制详解 - 走向架构师之路 - 博客频道 - CSDN.NET 最近发现几起对ThreadPoolExecutor的误用,其中包括自己,发现都是因为没有仔细看 ...

  5. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  6. iOS的消息转发机制详解

    iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法:或者,还有另外的方法,由于Objec ...

  7. 【转】java的动态代理机制详解

    java的动态代理机制详解   在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们 ...

  8. java异常处理机制详解

    java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...

  9. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

随机推荐

  1. Web开发经验谈之F12开发者工具/Web调试[利刃篇]

    引语:如今的整个Web开发行业甚至说整个软件开发行业,已经相当成熟,基本上已经很少找不到没有前人做过的东西了,或者换句话说,你想要实现的功能,你总能在某个地方搜索到答案,关键是你有没有这个时间精力去搜 ...

  2. mongodb3.x主从配置及备份

    本文将介绍下mongodb主从配置及备份 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关 ...

  3. 从零开始学 Spring Boot

    1.下载 spring-tool-suite https://spring.io/tools3/sts/legacy 2.解压运行 sts-bundle\sts-3.9.7.RELEASE\STS.e ...

  4. springboot + mybatis

    这两天启动了一个新项目因为项目组成员一直都使用的是mybatis,虽然个人比较喜欢jpa这种极简的模式,但是为了项目保持统一性技术选型还是定了 mybatis.到网上找了一下关于spring boot ...

  5. Ubantu 16.04升级内核版本和还原到升级之前的内核版本的方法

    一.查看系统信息 1.查看发布版本: 命令: lsb_release -a 运行结果: / 2.查看内核版本: 命令: uname -sr 运行结果: 二.升级内核的方法 1.内核下载地址:http: ...

  6. nmcli工具详解

    目录 1. nmcli 安装 2. nmcli 基本选项 3. general 常规选项 3.1 status 3.2 hostname 3.3 permissions 3.4 loggin 4. n ...

  7. 使用 Linux 自带的 logrotate 程序来控制日志文件尺寸

    1. 编写配置文件,内容如下(以 Amadeus 系统为例): 编写配置文件,放在 /etc/logrotate.d/xxxx 下,其中 xxxx 是自己取的名字,无需后缀.例如 Amadeus 系统 ...

  8. EOS生产区块:解析插件producer_plugin

    producer_plugin是控制区块生产的关键插件. 关键字:producer_plugin,同步区块的处理,pending区块,生产区块,最后不可逆区块,生产循环,生产安排,水印轮次,计时器,确 ...

  9. 自己动手实现java数据结构(七) AVL树

    1.AVL树介绍 前面我们已经介绍了二叉搜索树.普通的二叉搜索树在插入.删除数据时可能使得全树的数据分布不平衡,退化,导致二叉搜索树最关键的查询效率急剧降低.这也引出了平衡二叉搜索树的概念,平衡二叉搜 ...

  10. Netty 超时机制及心跳程序实现

    Netty 超时机制的介绍 Netty 的超时类型 IdleState 主要分为: ALL_IDLE : 一段时间内没有数据接收或者发送 READER_IDLE : 一段时间内没有数据接收 WRITE ...