1.屏障消息
屏障消息也叫同步屏障消息,作用是提升异步消息的执行优先级的。
首先假设有这样一种场景,在主线程的MessageQuee里面存在很多个消息在排队等待处理,然后这个时候我们去给主线程发送了一条刷新UI的Message,那么这条消息就需要高优处理。
为了实现这一效果,我们需要做3件事情:
1.1.发送屏障消息
给对应的MessageQueue发送一条屏障消息,以ViewRootImpl的scheduleTraversals方法举例:
//发送同步屏障消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
这里的mTraversalBarrier是返回回来的一个token标志,在后续使用完屏障消息后,需要用这个token去移除屏障消息。
1.2. 发送一条异步消息
首先我们需要知道的是,我们正常往handler发送的消息都是同步消息,即Message中的变量isAsynchronous是false的,只有当isAsynchronous的值是 true,才表示是一个异步消息。
我们可以通过设置这个属性,来标记消息是否是异步消息:
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
1.3. 移除屏障消息
使用完屏障消息后,需要手动移除,避免不能处理同步消息的情况发生:
//移除同步屏障消息
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
1.4.屏障消息的运行逻辑
Message next() {
......
int nextPollTimeoutMillis = 0;
for (;;) {
......
// 阻塞,nextPollTimeoutMillis为等待时间,如果为-1则会一直阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
// 下面的代码目的是获取一个可用的消息,如果找到就return,
// 没找到就继续后面我省略的代码(省略了IdHandler的相关代码)
// 获取时间,还是通过uptimeMillis这个方法
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 如果队列头部消息为屏障消息,即“target”为空的消息,则去寻找队列中的异步消息
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