Java中的Handle机制
传送门:https://www.jianshu.com/p/592fb6bb69fa
传送门:https://www.jianshu.com/p/9631eebadd5c
Handler的PostDelayed底层实现原理#
Handler的PostDelayed方法参数是一个Runnable对象。delayMillis为延迟时间,PostDelayed函数实际是调用的SendMessageDelayed方法
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
Runnable会被getPostMessage()函数封装在Message对象的Callback属性中。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
SendMessageDelayed函数会调用SendMessageAtTime, SendMessageAtTime函数会计算出(当前时间+延迟时间 )这个消息需要在什么时间执行作为参数传递。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
SendMessageAtTime会继续调用enqueueMessage函数
sendMessageAtTime(Message msg, long uptimeMillis)
{
MessageQueue queue
enqueueMessage(queue, msg, uptimeMillis);
}
enqueueMessage将消息发送到handle对应的线程消息队列MessageQueue中,并将发送消息的Handler对象封装到message消息对象的target字段。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 把发送消息的 handler对象封装到到 msg.target 属性中
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
然后Looper循环器(相当于windows消息机制中的消息循环)会从MessageQueue消息队列中取出Message消息。并通过执行msg.target.dispatchMessage(msg)调用handler对象的dispathchMessage方法。
public static void loop() {
final Looper me = myLooper(); // 返回当前 looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { // 循环取出queue 中的msg
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
。。。
final long end;
try {
msg.target.dispatchMessage(msg); // 使用发送消息的 handler 分发消息
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.....
msg.recycleUnchecked();
}
}
然后handler的dispathMessage方法会判断msg的类型,如果msg.callback不为NULL(也就是我们的Runnable对象),则执行handleCallback(msg)
/*
* 根据 msg 的不同类型分发消息
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//
handleCallback(msg);// 在handler.post(runnable)或 postDelayed(runnable,1000)的时候会执行到这里
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleCallback会执行Message.callback.run()也就是Runnable对象的run方法。
需要注意的问题#
handle与looper绑定#
handle是与looper绑定的,而looper是与创建looper的线程绑定的。创建handle的时候可以指定其所绑定的looper,如果使用无参构造创建handle则其默认使用当前线程的looper与handle绑定。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
......
//得到当前线程的Looper,其实就是调用的sThreadLocal.get
mLooper = Looper.myLooper();
// 如果当前线程没有Looper就报运行时异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 把得到的Looper的MessagQueue让Handler持有
mQueue = mLooper.mQueue;
......
}
使用handle发送消息时,消息会被发送到其绑定的looper所在的线程,而不是创建handle所在的线程。
子线程调用Toast#
线程调用Toast.show需要其先创建looper,因为Toast.show需要通过handle将消息发送到Toast.show调用线程的Looper消息循环中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-04-12 Smss.exe加载win32k.sys过程总结
2021-04-12 ZwQuerySystemInformation枚举内核模块