介绍
Handler机制的作用:实现线程间通信的
如何实现Handler机制:
简单模型
Handler、Looper、MessageQueue、Message
Handler:消息的处理者或者消费者,持有Looper的引用
Looper:通过loop()不停的读取MessageQueue消息,让Message.target(Handler)进行处理消息
MessageQueue:由链表实现的消息队列,方便插入和删除
Message:关键字段
- when:用作消息延时使用
- mCallBack:消息回调监听
- target:自定义其为消息来源,当为null表示屏障消息
- What、arg1、arg2、obj等
消息类型
- 同步消息:按顺序执行的普通消息
- 屏障消息:开启屏障、关闭屏障,开始屏障:表明要优先执行异步消息了,取消屏障:继续执行普通消息
- 异步消息:优先执行的消息,如帧率更新ui
发送消息
非延时消息:when= 当前时间 +0
延时消息:when= 当前时间+延时时间
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
入队列:消息插入到应该在的位置,如果队列正在阻塞中,唤醒队列
**boolean enqueueMessage(Message msg, long when) {
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) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
出队列:messageQueue.next()
- 普通消息:判断when和当前时间比,大于当前时间开始阻塞知道,时间到达,反之直接当条消息
- 屏障消息:target为null表示屏障消息,遍历出消息队列里吗的第一条异步消息执行
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}**
分发消息
Looper的loop方法调用
message.target.dispatchMessage()
Handler的方法dispatchMessage()
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//当消息中有callback直接回调消息中的
handleCallback(msg);
} else {//反之
if (mCallback != null) {//当前handler全局中有定义Callback
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//回调该方法
}
}
高级问题:
如何监听方法耗时,通过handler机制实现Printer接口
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
如何屏障消息区分
target=null
如何区分异步消息
isAsynchronous()方法
如何实现帧率优先
Vsync垂直同步信号监听,Choreographer.FrameCallback doFrame监听接口回调时,先发送屏障消息插入在对列头,然后在发送异步消息