Handler源码分析之二 异步消息的处理

再来看看removeSyncBarrier():

//这个token就是我们上面保存的
public void removeSyncBarrier(int token) {
synchronized (this) {
//遍历删除这个token对应的msg
Message prev = null;
Message p = mMessages;
//只要p.target!=null || p.arg1!=token就一直找,因为上面我们分析了同步屏障的target=null,并且arg1=token
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
//检测队列
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "

  • " barrier token has not been posted or has already been removed.");
    }
    final boolean needWake;
    //移除同步屏障消息
    if (prev != null) {
    prev.next = p.next;
    needWake = false;
    } else {
    mMessages = p.next;
    needWake = mMessages == null || mMessages.target != null;
    }
    //回收
    p.recycleUnchecked();

//如果需要唤醒,则唤醒等待
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}

然后看mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);第一个参数是个int,第二个参数mTraversalRunnable是个Runnable,代码如下:

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}

void doTraversal() {
if (mTraversalScheduled) { //不在执行中才执行
mTraversalScheduled = false; //更新标记为执行中
//从mHandler的MesssageQueue中移除同步屏障,还记得刚刚添加同步屏障的代码吗
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
//开始遍历布局
performTraversals();
}
}

//这个方法对view进行了测量,布局和绘制,我们后面会细讲
private void performTraversals() {

performMeasure();

performLayout();

performDraw();

}

我们来看下Choreographer类的部分关键代码:

class Choreographer {
public static final int CALLBACK_INPUT = 0;
public static final int CALLBACK_ANIMATION = 1;
public static final int CALLBACK_INSETS_ANIMATION = 2;
public static final int CALLBACK_TRAVERSAL = 3; //这是刚刚的第一个参数
public static final int CALLBACK_COMMIT = 4;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
private final CallbackQueue[] mCallbackQueues;
private final FrameHandler mHandler;
private final FrameDisplayEventReceiver mDisplayEventReceiver;

private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;

mHandler = new FrameHandler(looper);

//这里初始化mDisplayEventReceiver
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;

mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());

//这里对mCallbackQueues进行初始化,直接new出来一个长度为5的数组,并且初始化5个元素,为什么长度是5?因为上面说了CALLBACK_LAST=4
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}

//这就是刚刚调用的方法
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0); //第四个参数是0
}

public void postCallbackDelayed(int callbackType,Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException(“action must not be null”);
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException(“callbackType is invalid”);
}

postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}

//最终调到这里
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis(); //获取当前时间
final long dueTime = now + delayMillis; //delayMillis = 0,所以dueTime = now
//这是个数组 callbackType是CALLBACK_TRAVERSAL,dueTime=0,action就是那个mTraversalRunnable
//这里就是将这个mTraversalRunnable保存在CALLBACK_TRAVERSAL对应的集合里了
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

if (dueTime <= now) { //true
scheduleFrameLocked(now); //跑这里
} else {
//否则通过Handler发送出去
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}

//接着看
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
//看这里
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); //msg.what = MSG_DO_SCHEDULE_VSYNC
msg.setAsynchronous(true); //标记为异步消息!! 前面我们加了个同步屏障了的
mHandler.sendMessageAtFrontOfQueue(msg); //发送,这个mHandler是FrameHandler
}
} else {
final long nextFrameTime = Math.max(mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
}

接着来看FrameHandler的代码:

private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC: //跑到了这里
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}

接着看

void doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}

private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}

//来看下scheduleVsync方法:
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "

  • “receiver has already been disposed.”);
    } else {
    //这里直接调用了native的方法,native调用完成会回到
    nativeScheduleVsync(mReceiverPtr);
    }
    }

native完事后会回调到FrameDisplayEventReceiver.onVsync()里面:

private final class FrameDisplayEventReceiver extends DisplayEventReceiverimplements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;

public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
}

@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
long now = System.nanoTime();
if (timestampNanos > now) {
timestampNanos = now;
}

if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "

  • “one at a time.”);
    } else {
    mHavePendingVsync = true;
    }

mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this); //这里的第二个参数是this,意味着msg.callback = this,那么就会跑到自己的run函数
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

@Override
public void run() {
//跑到这里了
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}

void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
…省略计算时间的代码…
//下面开始执行事件顺序为: 1 输入事件 2 动画 3 布局
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, “Choreographer#doFrame”);
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);

mFrameInfo.markPerformTraversalsStart();
//TAG: CALLBACK_TRAVERSAL,还记得这个TAG吗,我们看这里即可
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}

void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
//这里根据callbackType取出所有事件,这里的type是:CALLBACK_TRAVERSAL
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
…省略部分代码…
}
try {
//遍历取出所有事件,执行,还记得我们之前的那个:mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)吗?
//第二个参数就是i一个i饿runnable,就会被执行,也就是执行到我们的traversal()里去了,最终就会去测量、布局、绘制
for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}
} finally {
…回收callback…
}
}

通过以上分析我们了解到: Android在布局的时候使用了异步消息,为什么要使用异步消息呢,有什么好处,答案就是:异步消息会被优先处理,比如当前MessageQueue中有100个消息,这时候有个布局消息来了,正常的话要等待100个执行完,如果是异步消息,则可以优先执行,这样UI就不会因为消息过多而卡顿,这就是优点,我们再来看看MessageQueue.next的代码:

Message next() {
…省略部分代码…
for (;😉 {
…省略部分代码…
synchronized (this) {
final long now = SystemClock.uptimeMillis(); //记录当前时间
Message prevMsg = null;
Message msg = mMessages; //取出第一条消息,也就是队头消息

//msg.target == null! 上面分析过,这是一个同步屏障,而同步屏障后面一般会有一个人异步消息,同步屏障的目的就是为了标记后面有个异步消息的
if (msg != null && msg.target == null) { //如果有同步屏障,那么就找异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous()); //果然在这里,只要不是异步消息,就一直找,直到找到为止
}

//开始处理消息
if (msg != null) {
…处理msg…
} else {
// 标记为-1无限等待
nextPollTimeoutMillis = -1;
}
…省略部分代码…
}
…省略处理空闲消息的代码…
}
}

上面省略了部分代码,主要分析了 异步消息是被优先执行的,而且异步消息都跟在同步屏障后面的

2 为什么要把Looper放在ThreadLocal里面

我们先来看怎么把Looper放在ThreadLocal里面的? Looper.prepare()

static final ThreadLocal sThreadLocal = new ThreadLocal();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException(“Only one Looper may be created per thread”);
}
sThreadLocal.set(new Looper(quitAllowed));
}

ThreadLocal.set()

public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

ThreadLocalMap.getMap() 可以看到Thread有一个成变量ThreadLocalMap

学习路线+知识梳理

花了很长时间,就为了整理这张详细的知识路线脑图。当然由于时间有限、能力也都有限,毕竟嵌入式全体系实在太庞大了,包括我那做嵌入式的同学,也不可能什么都懂,有些东西可能没覆盖到,不足之处,还希望小伙伴们一起交流补充,一起完善进步。

这次就分享到这里吧,下篇见
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值