刚开始学安卓,零零散散把平时学到的一些知识点总结了一下,希望能有些帮助吧。本篇文章主要总结了Android中的Handler消息处理机制,主要参考了李刚的《疯狂Android讲义》和任玉刚的《Android开发艺术探索》。个人水平有限,如果有不对的地方,欢迎大家批评指正。好啦,下面开始正文。
我们知道,Android不允许在主线程中进行耗时操作,因此例如访问网络、读取文件等耗时的I/O操作都需要在子线程中进行。当耗时操作完成之后,我们很可能需要在UI上作出一些改变,但是由于Android开发规范的限制,我们不能在子线程中访问UI组件,否则会触发程序异常。那么我们在子线程中操作的结果如何反映到主线程的UI界面上呢?这时候我们就可以使用Handler来进行处理。
Handler通过传递和处理Message消息,实现线程之间的切换,同时需要底层的MessageQueue来存储Message消息,通过Looper无限循环来查找是否有新的消息。下面我们就来看看这几个对象的主要功能,还有Handler消息处理机制的工作原理。
Message:消息
主要功能
- 由Handler发送并且处理的对象,主要包含消息ID、以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
常用的属性和方法
- Message.what属性,为Message添加ID
- Message.target,发送消息的Handler对象
- Message.setData(Bundle bundle)方法,通过Bundle传递数据
Handler
主要功能
- 负责Message消息的发送和处理。
- Handler的正常工作需要依赖于Looper,因此在创建Handler的线程中,必须先创建Looper对象,否则将会出现异常。
- 在主UI线程中,系统已经初始化一个Looper对象,可以直接创建并使用Handler。但是在自己开启的子线程中,必须创建Looper对象才可以正常使用Handler。
常用方法
发送消息
- sendEmptyMessage(int what),发送空消息
- sendEmptyMessageDelayed(int what, long delayMillis),延迟发送的空消息
- sendMessage(Message msg),发送消息
- sendMessageDelayed(Message msg, long delayMillis),延迟发送的消息
处理消息
- handleMessage(Message msg),对特定的Message进行处理
判断是否有消息
- hasMessage(int what)
- hasMessage(int what,Object object)
MessageQueue消息队列
主要功能
- 用来存放Handler发送过来的消息,并按照FIFO(先入先出)的规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等Looper的抽取。
常用方法
- enqueueMessage(Message msg,long when),往消息队里中插入一条消息,按照发送的时间when排列
- next(),读取消息,通过无限循环的方式,读取消息队列中的内容,如果有消息,则返回该消息并从消息队列中删除该消息,如果没有消息,则一直阻塞在那里。
Looper
主要功能
- 不断从MessageQueue中抽取Message并交给Handler处理。
- 一个线程中的MessageQueue需要一个Looper进行管理。Looper是当前线程创建的时候产生的(UI Thread即主线程是系统帮忙创建的Looper,而如果在子线程中,需要手动在创建线程后立即创建Looper[调用Looper.prepare()方法])。也就是说,会在当前线程上绑定一个Looper对象。
常用方法
- Looper.prepare(),创建Looper。创建Looper时,会在其内部创建一个MessageQueue对象。
- Looper.loop(),启动Looper。会调用MessageQueue中的next()方法,无限循环读取消息。如果有新消息,则将next()方法返回的Message对象交给Handler进行处理。没有没有新消息,next()方法阻塞,loop方法也阻塞。如果next()返回null,则跳出loop()方法,结束循环。
- Looper.quit()或者Looper.quitSafely(),退出Looper。会调用MessageQueue的对应方法,使next()返回null。
工作流程
-
创建Looper对象:因为Handler的使用需要依赖于Looper,因此需要现在需要使用Handler的线程中通过Looper.prepare()方法创建Looper对象,并且通过Looper.loop()开启循环。对于主线程还有HandlerThread,这两种线程里面都已经初始化了Looper对象,并且loop方法也已经开启,因此在这两种线程中可以直接创建Handler对象,否则必须先创建Looper。
-
在初始化Looper的线程中创建Handler对象。在其构造函数中,获取到Looper对象、MessageQueue对象(从Looper中获取的),并将handler作为message的标签设置到msg.target上
-
发送消息:通过Handler的sendMessage()方法发送消息。sendMessage(Message msg)最终都会调用MessageQueue的enqueueMessage()方法将消息插入到消息队列中,依据传入的时间进行消息入列。
-
轮询消息:在Looper.loop()方法中,获取到MessageQueue对象后,会调用MessageQueue的next()方法从中取出消息(Message msg = queue.next())。Loop()方法是无限循环的,而next()方法也是无限循环的。如果没有没有新消息,next()方法阻塞,loop方法也阻塞。如果有新消息,则获取next()方法返回的Message对象,调用msg.target.dispatchMessage(msg)方法交给Handler进行处理。如果next()返回null,则跳出loop()方法,结束循环。
-
dispatchMessage(msg)方法的执行过程:先判断msg的callback是否为空,不为空就调用Message的handleCallback()方法来处理;再判断mCallback是否为空,不为空就调用mCallback的handleMessage()方法来处理;最后调用Handler的handleMessage()方法来处理
6.结束Looper对象。因为Looper是通过无限循环的方式来判断消息队列中是否有新消息,当程序处理完成之后,最好调用Looper.quit()或者Looper.quitSafely()方法退出Looper,避免浪费系统资源。
主线程Handler的消息处理机制原理:
- 在创建Activity之前,当系统启动的时候,先加载ActivityThread这个类,在这个类中的main函数,调用了Looper.prepareMainLooper()方法创建主线程的Looper以及MessageQueue对象,并通过Looper的loop()方法开启主线程的消息循环。
- ActivityThread的Handler就是ActivityThread.H,其内部定义了一组消息类型,主要包含四大组件的启动和停止过程。
- 系统的某些组件或者其他的一些活动等发送了系统级别的消息,这个时候主线程中的Looper就可以进行轮询消息,并调用msg.target.dispatchMessage(msg)(msg.target即为handler)进行分发消息,并通过handler的handleMessage方法进行处理;所以会优于我们自己创建的handler中的消息而处理系统消息。
网友评论