handler消息处理机制
handler是什么?
Handler是一个在消息处理机制中负责发送和处理消息的类,是消息处理的关键。
消息处理涉及的主要类
- Handler:负责发送消息和处理消息
- Looper:内置一个死循环,可以不断的取出消息并通知handler处理消息,是handler起作用的基础
- Message:消息实体类
- MessageQueue:消息队列,负责存储消息
消息处理的基本原理
Thread、Handler、Lopper、MessageQueue对应关系
一个Lopper对应一个MessageQueue,因为Looper内置了一个消息队列。
一个Thread只能有一个Lopper。
一个Handler对象对应一个Thread和Thread的消息队列(但是一个Thread内可以有多个Handler)。当你创建一个Handler时,它就和Thread的消息队列绑定在一起。
特别注意:Handler虽然和Looper是一一对应的,但是Hanlder本身并不含有Looper,Looper是通过线程内部的存储类存储在Thread里的的,而Looper内置了一个消息队列。
消息传递基本思想
在线程B中获取属于线程A的handler,在B中创建的message可以通过调用handler.sendmessage(message对象)将消息添加到A线程的消息队列中去,A线程的Looper循环会取出消息并通知hanlder去处理消息,调用回调函数handler.handleMessage(用户一般要重写此方法)去处理消息。所以就实现了把B线程的数据封装到message中传递给线程A,通过线程A中重写handler的handleMessage方法在线程A中处理消息。
handler消息处理机制能做什么?
- 实现消息的异步处理,例如将子线程的数据通过Message传递到主线程中
- 一般来说UI控件只能在主线程中更新,但是在子线程中可以通过handler更新UI
Handler
Handler用于发送、处理消息,Handler本身不含有message,而message中有个target属性(hanlder类型),用于此条标识消息要由哪个handler去处理。
Handler有多个构造函数,但本质上都是外部传入一个Looper,Handler属于哪个现场取决于传入Looper属于哪个线程。
post(runable) //发送消息,Runnable是消息回调,经过消息循环引发消息回调函数执行;
sendMessage(message) //发送消息,经过消息循环派发消息处理函数中处理消息;
dispatchMessage(messsage) //派发消息,主要作用就是根据情况调用回调函数。
//若是post或带有回调函数则执行回调函数,否则执行消息处理函数Handler的handleMessage(通常派生类写)。
sendMessage和post两种发消息的本质是一样的,都是发送一个Message。只是post(runable r)方法发送的是一个callback属性为r的message,两个方法发出的消息在loop取出后,最终都会交到dispatchMessage处理。
handler消息处理的流程图
dispatchMessage(派发消息)源码分析
从代码中可以看到message本身有一Runable接口,只有它为空则执行handlemessage。
hanlder本身包含一个回调函数handlemessage,它本身又包含一个callback接口,接口里面又是一个handkemessage回调函数,到底执行哪个handlemessage就在dispatchMessage中判断,判断优先级是:消息回调 > handler的callback的回调 > handler本身回调
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) { //首先判断消息本身Runable是否为空,不为空就只执行消息的callback(Runable类型)
handleCallback(msg);
} else {
if (mCallback != null) { //如果handler的callback接口不为空,则执行hanlder的callback的回调函数
if (mCallback.handleMessage(msg)) {
return; //再如果callback的回调函数中返true,则不执行hanlder本身的回调函数
}
}
handleMessage(msg); //当消息的callback为空且handler的callback也为空或者,才执行handler本身的回调函 数
}
}
Looper
实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的,即没有Looper;
需要主动去创建(调用Lopper.prepare()),然后启动消息循环(调用Lopper.loop());与外部的交互通过Handler进行;
- Lopper.prepare() //为当前线程创建Lopper对象,实质上是new一个Looper然后通过当前线程内置的存储类ThreadLoacl保存该Looper,由于每个线程只能有一个Looper,所以通过prepare()创建Looper每次会判断当前线程是否有Looper,有则异常。
- Looper.loop() //通过死循环来不断取出当前线程Looper的消息队列中的消息,消息队列没有数据了就会挂起,核心代码如下图
- Looper.myLooper()//获取当前线程的Looper对象,底层是通过当前线程内置的线程存储类ThreadLoacl.get()来获得,获得的内容在Looper执行prepare()时通过ThreadLoacl.set()传入的Looper对象。
- Looper.myQueue()//获取Looper对应的消息队列
- Looper.getMainLooper()//获取主线程的Looper对象
拓展 —ThreadLocal
ThreadLoacal是Thread中内置的存储类,其本身并不存储数据,而是通过它内置的ThreadLoacaMap来存储数据的。
其主要方法有:
- set(T t) //设置线程变量
- get() //获得线程变量,调用前一定要调用set方法否则报空指针异常
在不同线程中执行get方法得到的值是不同的,得到的值是在对应线程set的值
Message
public final class Message implements Parcelable {
//标识消息
public int what;
int flags;
long when;
//传递简单数据
public int arg1;
public int arg2;
//传递较复杂数据 对象
public Object obj;
Bundle data;
//处理消息的目标Handler
Handler target;
//消息派发时 执行的Runnable对象
Runnable callback;
//使消息形成链表
Message next;
//建立一个消息pool,回收msg,以避免重复创建节约开销
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;
}
Message提供了obtain方法:通过obtain获取,可从MessagePool中获取(MessagePool类似数据库连接池)一个消息,可以节约开销。也通过myhanlder.obtain(),来获取一条target是myhanlder的对象的message。每条消息都有一个target,在某个handler发送消息(send或post)时,最终会将该handler赋值给该message.target,以便于在消息队列取出消息后直调用消息的target去处理消息。文章来源:https://www.toymoban.com/news/detail-760531.html
MessagePool
可以将创建的对象用完之后回收,以便再重复利用节约频繁创建释放开销。文章来源地址https://www.toymoban.com/news/detail-760531.html
public static void loop() {
while (true) {
//派发消息
msg.target.dispatchMessage(msg);
//消息处理完毕 回收
msg.recycle();
}
}
public void recycle() {
//回收Message 建立全局的MessagePool
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
到了这里,关于Android之handler消息处理机制详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!