- Handler
- MessageQueue
- Looper
- loop(): 循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用
- myLooper(): 获取当前 Looper
- myQueue(): 获取当前 MessageQueue
- prepare(): 创建 Looper, 用于在子线程创建子线程的 Looper
- getMainLooper(): 获取主线程 Looper
- getThread(): 获取当前线程
- isCurrentThread(): 判断是否是当前线程
- quit()/quitSafely(): 两者区别在于 quit 会回收所有 Message, quitSafely 只会回收当前时间后的 Message
- Message
Handler
什么是 Handler
Handler 是 Android 消息处理机制中负责发送消息和处理消息的环节
Handler 主要有两个用途:
- 计划
Message
和Runable
在将来的某个时刻执行 - 在与您自己的线程不同的线程上发送消息
Handler 使用方式
Handler 的构造方法里 Handler()
不推荐使用, 在 Handler 构建期间隐式选择 Looper 可能会导致以下错误:运行时会静默丢失操作(如果 Handler 不期望新任务并退出),崩溃(如果在没有 Looper 处于活动状态的线程上创建了 Handler )或竞争条件, Handler 与之关联的线程不在作者预期的范围内
推荐使用指定 Looper 的构造方法 Handler(Looper looper)
val handler: Handler = object : Handler(Looper.getMainLooper()){
// 处理已发送的消息
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
println(">>>>> Handler:" + Thread.currentThread().name)
}
}
// 发送空消息
handler.sendEmptyMessage(0)
// 发送消息
handler.sendMessage(message)
handler.post {
// Runnable 代替了 handleMessage 来直接处理此次 Runnable 消息
// 此方式在子线程有些用途, 在主线程就显得多次一举
}
/**
* 子线程创建 Handler
*/
var handler: Handler? = null
val thread = object : Thread("ThreadA") {
override fun run() {
super.run()
Looper.prepare()
handler = object : Handler(Looper.myLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
println(msg.toString())
}
}
Looper.loop()
}
}
thread.start()
/**
* 通过 HandlerThread 创建 Handler
*/
val handlerThread: HandlerThread = HandlerThread("HandlerThread")
handlerThread.start()
val handler: Handler = object : Handler(handlerThread.looper){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
println(">>>>> Handler:" + Thread.currentThread().name)
}
}
Handler 解析
Handler 的 send 和 post 系列方法的实质
Handler 的 send 和 post 系列方法最后都是把数据封装到了 Message 内
Handler 的 send 和 post 系列方法的实质实际上都是调用了 sendMessageAtTime(Message msg, long uptimeMillis)
, 通过 uptimeMillis 来对消息队列进行排序.uptimeMillis = SystemClock.uptimeMillis() + delayMillis
, 设备开机到现在的时间 + 延迟时间
Handler#dispatchMessage(Message)
Looper将 Message 对象从 MessageQueue 中取出来,并将其交给 Handler#dispatchMessage(Message)
方法而不是交给 Handler#handleMessage(Message)
, 从源码里就可以看出:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
参考链接
https://www.jianshu.com/p/f70ee1765a61
https://blog.csdn.net/qq_37321098/article/details/81535449
MessageQueue
MessageQueue 消息队列, 用于储存 Message. Message 添加到消息队列时会先判断队列里是否还有 Message, 若没有则直接添加队列, 若有则对其根据 when 进行排序后添加到队列
注: 消息队列为后进先出
添加消息到队列
队列中的Message触发时间是有先后顺序的。当消息加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序(内部遍历队列中Message,找到when比当前Message的when大的Message,将Message插入到该Message之前,如果没找到则将Message插入到队列最后)。一般是当前队列为空的情况下,next那边会进入睡眠,需要的时候MessageQueue这边会唤醒 next()
方法
/**
* 通过 Handler 将消息添加到队列
*/
boolean enqueueMessage(Message msg, long when) {
// 每一个普通Message必须有一个target-handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//已在使用状态
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//消息在退出状态->被回收到消息池
if (mQuitting) {
msg.recycle();
return false;
}
//标记使用状态,记录执行时间
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//p为null代表MessageQueue没有消息或者msg的触发时间是队列中最早的
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; //当阻塞时需要唤醒
} else {
//将消息按时间顺序插入到MessageQueue。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
————————————————
版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449
取出消息
next()
方法中,做了异步Message消息的判断, 特殊的是这个Message没有设置target,即 msg.target 为null
//不停提取下一条message
Message next() {
final long ptr = mPtr;
//判断是否退出消息循环
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
//代表下一个消息到来前,还需要等待的时长
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//native层阻塞cpu。如果被阻塞,唤醒事件队列
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//如果当前消息是异步消息,都将赋值给prevMsg,过滤掉,直到取到了非异步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//获取到了非异步消息
if (msg != null) {
//任务执行时间大于现在的时间
if (now < msg.when) {
//设置下一次轮询的超时时长
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;//指定为非阻塞任务
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
//设置消息的使用状态,即flags |= FLAG_IN_USE
msg.markInUse();
return msg; //成功地获取MessageQueue中的下一条即将要执行的消息
}
} else {
//表示消息队列中无消息,会一直等待下去
nextPollTimeoutMillis = -1;
}
......
//IdleHandler为发现线程何时阻塞的回调接口
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; //去除handler引用
boolean keep = false;
//queueIdle返回true会被空闲的处理器处理,false就会被移走
try {
keep = idler.queueIdle(); //idle时执行的方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler); //被移走
}
}
}
//重置idle handler个数为0,保证不会再次重复运行
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
————————————————
版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449
移除消息
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
//从消息队列的头部开始,移除所有符合条件的消息
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
//移除剩余的符合要求的消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
参考链接
https://blog.csdn.net/qq_37321098/article/details/81535449
Looper
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环。若要创建一个,请prepare()
在要运行循环的线程中进行调用 ,然后 loop()
让其处理消息,直到循环停止为止
与消息循环的大多数交互是通过 Handler 类进行的
作用: 负责读取MessageQueen中的消息,读到消息之后就把消息交给Handler去处理
loop(): 循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用
myLooper(): 获取当前 Looper
myQueue(): 获取当前 MessageQueue
prepare(): 创建 Looper, 用于在子线程创建子线程的 Looper
getMainLooper(): 获取主线程 Looper
getThread(): 获取当前线程
isCurrentThread(): 判断是否是当前线程
quit()/quitSafely(): 两者区别在于 quit 会回收所有 Message, quitSafely 只会回收当前时间后的 Message
Message
创建 Message
// 创建 Message
val message = Message.obtain()
val message = handler.obtainMessage()
Message 解析
/**
* 用于分类 Message 的类型
*/
public int what;
/**
* 如果您只需要存储几个整数值,那么arg1和arg2是使用
* {@link #setData(Bundle) setData()}的较低成本的替代方法
*/
public int arg1;
/**
* 如果您只需要存储几个整数值,那么arg1和arg2是使用
* {@link #setData(Bundle) setData()}的较低成本的替代方法
*/
public int arg2;
/**
* 要发送给收件人的任意对象
*/
public Object obj;
/**
* 传递 Messenger, 用于通过 Messenger 回复消息
*/
public Messenger replyTo;