Android-怎么就不卡了呢之Choreographer,flutter蓝牙

mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);//Message设置为异步
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}

接收到垂直同步信号后回调onVsync方法,这个方法使用handler发送带callback(Runnable类型,自身已继承)的message,最后run()中也是调用doFrame();(关于这个handler的这个操作详细信息逻辑,参照下面本文附录一 handler 分发message

这个message设置为了异步 (msg.setAsynchronous(true);)这意味这他有优先执行的权利,他是怎么被优先执行的呢?参照附录三 message的异步模式

综上,添加callback流程

Android-怎么就不卡了呢之Choreographer,flutter蓝牙

二、执行

doFrame

void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}

//当前时间
startNanos = System.nanoTime();
//当前时间和垂直同步时间
final long jitterNanos = startNanos - frameTimeNanos;
//垂直同步时间和当前时间的差值如果大于一个周期就修正一下
if (jitterNanos >= mFrameIntervalNanos) {
//取插值和始终周期的余数
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
//当前时间减去上一步得到的余数当作最新的始终信号时间
frameTimeNanos = startNanos - lastFrameOffset;
}
//垂直同步时间上一次时间还小,就安排下次垂直,直接返回
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}

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);

mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

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

if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "

  • (endNanos - startNanos) * 0.000001f + " ms, latency "
  • (startNanos - frameTimeNanos) * 0.000001f + " ms.");
    }
    }
  1. 第一步修正判断
  • 当前时间 startNanos = System.nanoTime();

  • 求当前时间和垂直同步时间的差值 :jitterNanos = startNanos - frameTimeNanos;

  • 垂直同步时间和当前时间的差值如果大于一个周期(jitterNanos >= mFrameIntervalNanos)就修正一下

  • 取插值和始终周期的余数:lastFrameOffset = jitterNanos % mFrameIntervalNanos;

  • 当前时间减去上一步得到的余数当作最新的始终信号时间:frameTimeNanos = startNanos - lastFrameOffset;

  • 垂直同步时间上一次时间还小,就安排下次渲染: frameTimeNanos < mLastFrameTimeNanos,直接返回

  1. 第二步‍执行callback callback的执行顺序是:
  • CALLBACK_INPUT输入时间优先级最高
  • CALLBACK_ANIMATION 动画的次之
  • CALLBACK_TRAVERSAL UI绘制布局的再次之
  • CALLBACK_COMMIT动画修正相关最后。

2.2 doCallbacks();

  • CallbackQueue[] mCallbackQueues在取特定类型(输入,动画,布局,Commit)的单向链表
  • 然后取出已到期的Callback/Runable执行

取出需要被执行的Actions

Action包装在CallbackRecord中,是一个单向列表,按照时间的大小顺序排列的。 取出待执行的Actions是通过CallBackQueue的extractDueCallbacksLocked()方法,可以把CallBackQueue看做是CallBack的管理类,其中还包括添加Action addCallbackLocked(),移除Action removeCallbacksLocked(),是否有带起的Anction hasDueCallbacksLocked()方法。

private final class CallbackQueue {
//链表头
private CallbackRecord mHead;
//是否存在已经到期的Action
public boolean hasDueCallbacksLocked(long now) {
return mHead != null && mHead.dueTime <= now;
}
//获取已经到期的Action
public CallbackRecord extractDueCallbacksLocked(long now) {

return callbacks;
}

//添加Action
public void addCallbackLocked(long dueTime, Object action, Object token) {

}
//移除Action
public void removeCallbacksLocked(Object action, Object token) {

}
}

执行Action

for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}

从callback中遍历出CallBcakRecord,挨个执行。

三、小结

  • Choreographer对外提供了postCallback等方法,最终他们内部都是通过调用postCallbackDelayedInternal()实现这个方法主要会做两件事情
  • 存储ActAndroid-怎么就不卡了呢之Choreographer,flutter蓝牙
    ion
  • 请求垂直同步,垂直同步
  • 垂直同步回调立马执行Action(CallBack/Runnable)。
  • Action一个动作内容的类型可能是
  • CALLBACK_INPUT输入时间优先级最高
  • CALLBACK_ANIMATION 动画的次之
  • CALLBACK_TRAVERSAL UI绘制布局的再次之
  • CALLBACK_COMMIT动画修正相关最后。
  • 复习Hanlder机制,我认为他是Android系统跑起来的大引擎终点关注下,handler对message的分发执行,以及“异步模式”。

附一、关于handler执行Message

下面是handler分发逻辑,Looper在MessageQueue得到要执行的message之后就会交给message的target(Handler类型)属性处理msg.target.dispatchMessage(msg);;

public void dispatchMessage(Message msg) {
//当msg的callback不为空的时候直接执行msg的callback它是一个Runnable对象
if (msg.callback != null) {
handleCallback(msg);
} else {
//然后再交给mCallBack,它是handler的一个属性,
//创建Handler的时候可以选择传入一个CallBack对象
//当callBack中handleMessage返回true的时候表示:True if no further handling is desired(不需要进一步处理)

if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//当mCallback处理返回为false的时候才去执行Handler自身的handleMessage()方法
handleMessage(msg);
}
}

关键逻辑在已注释,小结一下 handler的执行分发Message逻辑

  1. 如果message的callback(runnable)属性不为空,调用这个runable的run()方法执行

private static void handleCallback(Message message) {
message.callback.run();
}

当我们使用handler.post(Runnable r)方法时候就是将r设置给message的callback

  1. 上述条件不满足的情况下,如果handler自身的mCallback不为空的时候就会,将message交给mCallback处理,handlerMessage()结束。这个属性是在handler创建的时候传入的。mCallback是CallBack类型,他是handler的一个内部接口。

public interface Callback {
boolean handleMessage(Message msg);
}

3.当messaga 的callBak为空,且handler的mCallBack为空的时候就交给自己的handlerMessage()方法执行了。我们在自定义handler的时候可以重写这个方法对message进行相应的操作。

附二 、mFrameScheduled属性作用

  • 执行callcack的时候会判断mFrameScheduled属性如果为false表示没有安排渲染下一帧就直接返回,不执行。

void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}


mFrameScheduled = false;

}

  • 在scheduleFrameLocked()方法中,将mFrameScheduled值设置为ture表示安排了请求渲染下一帧。如果这时mFrameScheduled为true表示已经安排了下一帧那么就返回,不添乱!

附三、Handler机制的异步模式

作用

“异步模式”的作用就是优先,asynchronous 的message在异步模式下有优先执行的权。

用法

MessageQueue使用postSyncBarrier()方法添加屏障,removeSyncBarrier()方法移除屏障这个两个方法是成对使用的。

实现原理

  • messageQueued的postSyncBarrier方法向messagequeue的头部添加一个target属性为null的message
  • messageQueue的next()当碰到target为null的message的时候就只会在message链表中取出去“异步message”,而忽略普通的message,交给Looper做进一步分发处理。

Message next() {

for (;

上一篇:15-Netty心跳检测机制


下一篇:浅谈 Next 开发