Handler消息处理机制详解
之前一直只知道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消息处理机制详解的更多相关文章
- 【转载】Android异步消息处理机制详解及源码分析
PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...
- Android应用AsyncTask处理机制详解及源码分析
1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机 ...
- 【转载】Android应用AsyncTask处理机制详解及源码分析
[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个 ...
- ThreadPoolExecutor运转机制详解
ThreadPoolExecutor运转机制详解 - 走向架构师之路 - 博客频道 - CSDN.NET 最近发现几起对ThreadPoolExecutor的误用,其中包括自己,发现都是因为没有仔细看 ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- iOS的消息转发机制详解
iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法:或者,还有另外的方法,由于Objec ...
- 【转】java的动态代理机制详解
java的动态代理机制详解 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们 ...
- java异常处理机制详解
java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...
- 从mixin到new和prototype:Javascript原型机制详解
从mixin到new和prototype:Javascript原型机制详解 这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...
随机推荐
- spring框架学习笔记6:JDBC模板
JDBC模板:Spring中对数据库的操作. 这一部分对熟悉DBUtils的QueryRunner的开发者来说,非常简单 这是以前我简单写的dbutils的知识: http://www.cnblogs ...
- struts2框架学习笔记5:OGNL表达式
OGNL取值范围分两部分,root.Context两部分 可以放置任何对象作为ROOT,CONTEXT中必须是Map键值对 示例: 准备工作: public void fun1() throws Ex ...
- ASP.NET Core 2.2中的Endpoint路由
Endpoint路由 在ASP.NET Core 2.2中,新增了一种路由,叫做Endpoint(终结点)路由.本文将以往的路由系统称为传统路由. 本文通过源码的方式介绍传统路由和Endpoint路由 ...
- Linux - 快速进入目录的方法
cd命令技巧 直接进入用户的home目录: cd ~ 进入上一个目录: cd - 进入当前目录的上一层目录: cd .. 进入当前目录的上两层目录: cd ../.. 其他常用方法 利用tab键,自动 ...
- java微信分享
先吐槽一下!!! 哎,张小龙写的教程真差,要研究半天才能用上,大家按我的步骤12345,包你药到病除: 1.官方参考: https://mp.weixin.qq.com/wiki?t=resource ...
- nohup后台执行
由于使用nohup时,会自动将输出写入nohup.out文件中,如果文件很大的话,nohup.out就会不停的增大,这是我们不希望看到的,因此,可以利用/dev/null来解决这个问题. nohup ...
- Web渗透:PHP字符编码绕过漏洞总结
其实这东西国内少数黑客早已知道,只不过没有共享公布而已.有些人是不愿共享,宁愿烂在地里,另外的一些则是用来牟利. 该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有 ...
- .net core通过发布nuget实现引用项目
1 获取 api key 登录 https://www.nuget.org/account 进行api key获取操作 2 安装 nuget package explorer 3 进入要发布的项目目 ...
- 浅析mpvue的事件代理系统
前言 说来惭愧,用 mpvue 大半年,小程序快一年了,居然还试图用 event.stopPropagation 方法阻止事件冒泡,也是有点蠢.痛定思痛,写篇博文来认真捋一捋小程序的事件系统和 mpv ...
- 配置文件热加载的go语言实现
通常我们更新应用程序的配置文件,都需要手动重启程序或手动重新加载配置.假设一组服务部署在10台机器上,你需要借助批量运维工具执行重启命令,而且10台同时重启可能还会造成服务短暂不可用.要是更新配置后, ...