Choreographer机制和卡顿优化,java面试题及答案解析

本文详细解析了Android中Choreographer的机制,包括如何调度帧、VSYNC信号的工作流程以及如何处理VSYNC事件。在Choreographer的运行过程中,如果消息队列中有过多的消息,可能导致帧率下降并触发"Skipped"帧的警告,但这并不直接意味着UI卡顿,而是可能由消息阻塞引起。文章还介绍了两种卡顿优化方案,包括利用Looper日志和使用Choreographer.FrameCallback。通过对Choreographer的深入理解,有助于进行更有效的UI性能优化。
摘要由CSDN通过智能技术生成

mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

if (dueTime <= now) {

scheduleFrameLocked(now);

} else {

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);

msg.arg1 = callbackType;

msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, dueTime);

}

}

}

我们可以看到正常情况下会执行scheduleFrameLocked方法

private void scheduleFrameLocked(long now) {

if (!mFrameScheduled) {

mFrameScheduled = true;

if (USE_VSYNC) {

if (DEBUG_FRAMES) {

Log.d(TAG, “Scheduling next frame on vsync.”);

}

// If running on the Looper thread, then schedule the vsync immediately,

// otherwise post a message to schedule the vsync from the UI thread

// as soon as possible.

if (isRunningOnLooperThreadLocked()) {

scheduleVsyncLocked();

} else {

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);

msg.setAsynchronous(true);

mHandler.sendMessageAtFrontOfQueue(msg);

}

} else {

final long nextFrameTime = Math.max(

mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);

if (DEBUG_FRAMES) {

Log.d(TAG, “Scheduling next frame in " + (nextFrameTime - now) + " ms.”);

}

Message msg = mHandler.obtainMessage(MSG_DO_FRAME);

msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, nextFrameTime);

}

}

}

由于在4.1上是使用VSYNC信号的,所以就自然会调用scheduleVsyncLocked方法,会间接调用scheduleVsync方法

**

  • Schedules a single vertical sync pulse to be delivered when the next

  • display frame begins.

*/

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 {

nativeScheduleVsync(mReceiverPtr);

}

}

注意:这里的注释说的很清楚了,当下一帧来临时准备一个要分发的垂直同步信号,啥意思呢?简单来说就是当调用了nativeScheduleVsync方法时,当屏幕需要刷新的时候,也就是每隔16.6ms会通过native的looper分发到java层,从而调用java的方法,那是哪个方法呢?

// Called from native code.

@SuppressWarnings(“unused”)

private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {

onVsync(timestampNanos, builtInDisplayId, frame);

}

很明显是此方法

举个例子,比如屏幕显示的是第一帧,你在第一帧调用invalidate,其实并不是立即刷新的,而是在一帧会去注册一个Vsync(前提是这一帧cpu空闲情况下),当下一帧来临时也就是第二帧的时候会调用dispatchVsync此方法,当然这是一种比较简单的情况,复杂的等会说

那么来看一下调用的onVsync方法

public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {

// Ignore vsync from secondary display.

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值