handler消息处理机制
Handler是一个在消息处理机制中负责发送和处理消息的类,是消息处理的关键。
消息处理涉及的主要类
- Handler:负责发送消息和处理消息
- Looper:内置一个死循环,可以不断的取出消息并通知handler处理消息,是handler起作用的基础
- Message:消息实体类
- MessageQueue:消息队列,负责存储消息
消息处理的基本原理
Thread、Handler、Lopper、MessageQueue对应关系
一个Lopper对应一个MessageQueue,因为Looper内置了一个消息队列。
一个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
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消息处理的流程图
从代码中可以看到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对象。
拓展 —ThreadLocal
ThreadLoacal是Thread中内置的存储类,其本身并不存储数据,而是通过它内置的ThreadLoacaMap来存储数据的。
其主要方法有:
在不同线程中执行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去处理消息。
MessagePool
可以将创建的对象用完之后回收,以便再重复利用节约频繁创建释放开销。
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++;
}
}
原文地址:https://blog.csdn.net/qq_43800449/article/details/130447487
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_26212.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!