Handler消息传递机制——源码赏析
来源:互联网 发布:河南中小学生消防知 编辑:程序博客网 时间:2024/06/05 12:04
Android的消息处理有四个核心类:Handler 、Looper 、Message 、MessageQueue , 都在android.os包中
一、线程的魔法师 Looper
Looper字面 意思是循环者,它被设计用来使一个普通线程变成一个Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中) ,经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程,使用Looper类创建Looper线程很简单,代码如下:
通过上面两行代码普通线程就编程了Looper线程,看看这两行代码都干了些什么。
1)Looper.prepare();
通过上图可以看出,现在你的线程中有了一个Looper对象,他的内部维护了一个消息队列MQ. 一个Thread只能有一个Looper对象,为什么呢,我们来看下源码
通过源码可以看出,当我们调用Looper.prepare()时,内部会检查该线程中是否存在Looper对象,如果存在就会抛出:Only one Looper may be created per thread
2)Looper.loop();
调用loop方法后,Looper线程就开始真正工作了,它不断的从自己的MQ中取出队头的消息(及任务)执行。源码如下:
从源码中我们可以看出在116行我们得到当前的线程Looper,下面两行代码是得到当前looper的MQ,在123行我们可以清楚的看到里面是一个死循环,就是不断的从MQ中取出消息处理。在124行我们取出消息队列中的消息,137行非常重要,该行是将处理工作交给message的target,即后面将到的handler, 131行是我们记录的日志信息,了解即可。154行将发送出去的消息回收掉。
除了prepare()方法和loop()方法,Looper还提供了一些比较有用的方法,如:
Looper.myLooper() 得到当前线程的Looper对象
getThread() 得到Looper对象所属线程
quit() 结束Looper循环
到此我们该对Looper有了一个大概的了解,总结一下几点:
● 每个线程最多只能有一个Looper对象,他是一个ThreadLocal
● Looper内部有一个消息队列,loop()方法调用后,开始不断的从消息队列中取出消息执行
● Looper使一个普通线程变成一个Looper线程
那么我们该如何往MQ中添加消息呢?下面就用到了我们的Handler!
二、异步处理大师 Handler
handler扮演了往MQ中添加消息和处理消息的角色(只处理有自己发送的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程都是异步的。handler创建时会关联一个looper,默认的构造方法将关联当前的looper. 默认的构造方法:
从源码中我们可以看出在第195行将默认关联当前线程的looper, 196行是判断当前looper是否为空,200行代码非常重要,表示直接把关联的Looper的MQ当做自己的MQ,因此它的消息将发送到关联looper的MQ上。
下面我们为之前的代码加上handler
加入handler的效果图如下
可以看到,一个线程可以有多个handler ,但是只能有一个Looper
handler发送消息
msg.target.dispatchMessage(msg);
2.post发出的message,其callback为Runnable对象
Handler处理消息
说完了消息的发送,再来看下handler如何处理消息。消息的处理是通过核心方法dispatchMessage(Message msg)与钩子方法handleMessage(Messagemsg)完成的,见源码
可以看到,除了handleMessage(Message msg)和Runnable对象的run方法由开发者实现外(实现具体逻辑),handler的内部工作机制对开发者是透明的。这正是handler API设计的精妙之处!
Handler的用处
handler被描述为“异步处理大师”,这归功于Handler拥有下面两个重要的特点:
1.handler可以在任意线程发送消息,这些消息会被添加到关联的MQ上。
2.handler是在它关联的looper线程中处理消息的。
这就解决了android最经典的不能在其他非主线程中更新UI的问题。android的主线程也是一个looper线程(looper在android中运用很广),我们在其中创建的handler默认将关联主线程MQ。因此,利用handler的一个solution就是在activity中创建handler并将其引用传递给worker thread,worker thread执行完任务后使用handler发送消息通知activity更新UI。(过程如图)
下面给出sample代码,仅供参考:
当然,handler能做的远远不仅如此,由于它能post Runnable对象,它还能与Looper配合实现经典的Pipeline Thread(流水线线程)模式。
三、封装任务 Message
在整个消息处理机制中,message又叫task,封装了任务携带的信息和处理该任务的handler。message的用法比较简单,使用Message需要注意4点:
1、Message虽然也可以通过new来获取,但是通常使用Message.obtain()或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源;2、如果一个Message只需要携带简单的int型数据,应优先使用arg1和arg2属性来传递数据,这样比Bundle节省内存;3、尽可能使用Message.what来标识信息,以便用不同的方式处理Message。4、如果需要从工作线程返回很多数据信息,可以借助Bundle对象将这些数据集中到一起,然后存放到obj属性中,再返回到主线程。
- Handler消息传递机制——源码赏析
- Handler消息传递机制——源码赏析
- 【Android基础笔记18】Handler消息传递机制——源码赏析
- Android22_Handler消息传递机制——源码赏析
- Android 源码解析Handler消息传递机制
- 源码篇——Handler消息机制
- Handler消息传递机制
- Handler 消息传递机制
- Handler消息传递机制
- Handler消息传递机制
- Handler 消息传递机制
- Handler消息传递机制
- Handler消息传递机制
- Handler消息传递机制
- Handler 消息传递机制
- Handler 消息传递机制
- Handler消息传递机制
- Handler消息传递机制
- Java泛型(一) 泛型的基本使用和介绍
- hive权限问题
- 学生信息记录文件中
- table的 cellspacing 本质是 border-spacing
- Windows上安装Jekyll
- Handler消息传递机制——源码赏析
- ubuntu环境下VLFeat在MATLAB上的运行
- 天声人語 20141217
- 发送邮件编程原理
- 【Cocos2dx-Lua 脚本开发之二】Lua语言基础
- Java 中的继承
- Android shape的使用实现圆角,虚线,渐变等效果
- Java的equals和==问题
- ArcGIS教程:在ArcGIS下如何合并dem