Android-怎么就不卡了呢之Choreographer

渲染机制(二):Choreographer 源码解析 在引入 Vsync 之前,系统渲染一帧是通过Message来实现的,Msg中间没有间隔。但由于Msg的消费时长不确定,这直接导致了帧率不稳定,从而产生了Jank现象,画面撕裂等问题。为了优化这些问题,Android 在4.1之后引入了 `Choreographer + SurfaceFlinger + Vsync + TripleBuffer` 这一套机制,保证了 Android App 可以以一个稳定的帧率运行(60fps),减少帧率波动带来的不适感。 阅读详情

void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}

这个方法中先是做了一些判断,mFrameSceduled为false 并且hasDueCallbacksLocked()这个方法的返回值为true,看方法名就能猜出这个callback是否到期了,下面我们再分析这个。最终如果满足条件的情况下它会调用 scheduleFrameLocked()这个方法,咦这个方法眼熟不?对,没错,postCallbackDelayedInternal()方法中如果到期了的话就直接执行的那个方法。是时候看这个方法里面搞的什么事情了。

1.4 scheduleFrameLocked()

private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;//设置标记位,表示已经安排请求下一帧渲染了。
if (USE_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);
}
}
}

  • 这个方法的目的很明确就是安排,安排垂直同步而且立刻马上尽快。安排垂直同步的条件是USE_VSYNC为true,也就是设备支持垂直同步
  • 如果不是垂直同步就通过handler发送一个延时一个周期的消息安排垂直同步,这个Message的what值为 MSG_DO_FRAME,参照1.2的代码块对what为MSG_DO_FRAME的消息会去执行doFrame()方法。
  • 一个细节,当这个值mFrameScheduled为true的时候就直接返回不安排请求下一帧渲染了,如果为false,执行scheduleFrameLocked()方法继续执行,并且将其设置为ture;在什么时候设置为false的呢?详细细节看附录二

安排垂直同步的具体实现是FrameDisplayEventReceiver类他是DisplayEventReceiver的用于接收垂直信号

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

public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
mTimestampNanos = timestampNanos;
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 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》无偿开源 徽信搜索公众号【编程进阶路】 (Runnable类型,自身已继承)的message,最后run()中也是调用doFrame();(关于这个handler的这个操作详细信息逻辑,参照下面本文附录一 handler 分发message

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

综上,添加callback流程

二、执行

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()实现这个方法主要会做两件事情
  • 存储Action
  • 请求垂直同步,垂直同步
  • 垂直同步回调立马执行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的一个内部接口。

llback(Message message) {
message.callback.run();
}

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

  1. 上述条件不满足的情况下,如果handler自身的mCallback不为空的时候就会,将message交给mCallback处理,handlerMessage()结束。这个属性是在handler创建的时候传入的。mCallback是CallBack类型,他是handler的一个内部接口。
Choreographer机制和卡顿优化 Choreographer 是 Android 4.1 google的黄油计划新增的机制,用于配合系统的 VSYNC 中断信号。其主要用途是接收系统的 VSYNC 信号,统一管理应用的输入、动画和绘制等任务的执行时机。也就是(CALLBACK_INPUT,CALLBACK_ANIMATION,CALLBACK_TRAVERSAL,CALLBACK_COMMIT),而我们主要的用途就是来查看app的帧率情况,下面来具体分析下这个神秘的类 当我们进行invalidate或者requestLayout时,总会执行 阅读详情

相关推荐

Android屏幕刷新机制—VSync、Choreographer-全面理解!

上面讲到,Google在Android 4.1系统中对Android Display系统进行了优化:在收到VSync pulse后,将马上开始下一帧的渲染。即一旦收到VSync通知,CPU和GPU就立刻开始计算然后把数据写入buffer。本节就来讲 “drawing with VSync” 的实现——。Choreographer,意为 舞蹈编导、编舞者。在这里就是指 对CPU/GPU绘制的指导—— 收到VSync信号 才开始绘制,保证绘制拥有完整的16.6ms,避免绘制的随机性。

2401_84010865的博客 1355

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(mTimestampNa

m0_66155658的博客 927

Excel中如何快速地将成绩按比例来划分为等级?

问题介绍: 记录说明:班级里共有40个人,按最终总平均成绩从高到低划分等级,A等级30%,B等级50%,C等级20%。 部分成绩如下表所示: Excel中相关函数介绍: IF函数 IF函数有三个参数,语法如下: =IF(条件判断, 结果为真返回值, 结果为假返回值) 第一参数是条件判断,比如说“A1=">37”这种,判断TRUE或FALSE。如果判断是TRUE(结果为真)那么IF函数返回值是第二参数,否则(结果为假)返回第三参数。 如果省略了第三参数,则当结果为假时,会返回FALSE。 如果公式

Wendy的博客 1万+

Android 怎么就不卡了呢之Choreographer_choreography 安卓(1)

了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

2401_83974590的博客 903

Nvidia Isaac Sim安装与配置 入门教程 2024(2)

Isaac Sim 安装和配置教程将指导用户完成从下载软件到设置和运行仿真的全过程。教程内容包括安装必要的依赖项、配置系统环境、配置Omniverse环境以及调试和优化仿真环境的步骤。通过详细的操作步骤和图文并茂的说明,用户可以快速上手 Isaac Sim,构建出高质量的机器人仿真环境,实现其研究和应用目标。

m0_56661101的博客 2万+

永磁同步电机定子槽型设计实战:从梨形槽到矩形槽的NVH优化之路

本文深入探讨了永磁同步电机定子槽型设计在NVH优化中的关键作用,对比了梨形槽与矩形槽的性能差异。通过Ansys Maxwell仿真和实际案例,揭示了矩形槽在提升槽满率、降低电磁噪声方面的优势,并总结了五大设计黄金法则,为电机设计工程师提供了实用指导。

weixin_28740299的博客 493

Android 怎么就不卡了呢之Choreographer_choreography 安卓

/postCallbackDelayedInternal()方法中当未到期的时候发送过来的。//垂直同步时间和当前时间的差值如果大于一个周期就修正一下。//垂直同步时间上一次时间还小,就安排下次垂直,直接返回。//当前时间减去上一步得到的余数当作最新的始终信号时间。//是否存在已经到期的Action。//获取已经到期的Action。//当前时间和垂直同步时间。//取插值和始终周期的余数。//添加Action。//移除Action。

2401_85968790的博客 942

欧姆龙PLC与fanuc发那科机器人进行Ethrenet ip通信测试

近期在做发那科FANUC的通讯,会吧CC-LINK、Profibus-DP、Profinet I/O、DeviceNet、EtherNet/IP这些常用通讯做成文档发上来,大家喜欢的话可以关注 注:做对应的通讯,在机器人控制柜都需要安装对应的板卡以及软件功能 截图中的程序设置和机器人EDS插件在下面链接 https://download.youkuaiyun.com/download/gojava/13770799 PLC为主站 机器人为从站 一、硬件部分 欧姆龙PLC ...

七兔自习室 1万+

Android 怎么就不卡了呢之Choreographer_choreography 安卓(5)

了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

2401_83974607的博客 1177

COMSOL多物理场仿真:瓷绝缘子电热耦合建模与优化策略

本文详细介绍了使用COMSOL Multiphysics进行瓷绝缘子电热耦合仿真的完整流程与优化策略。文章阐述了电热耦合效应的工程意义,并逐步讲解了从几何建模、材料定义、物理场设置到边界条件与网格划分的关键步骤。重点分析了如何通过焦耳热耦合实现电场与温度场的双向交互,以及如何利用仿真结果进行参数化优化和瞬态故障模拟,为提升电力设备可靠性提供有效的数字化设计工具。

n8m7b6v5c4的博客 883

沉降预测算法-指数曲线法

沉降预测的指数曲线法原理和代码实现

yh523的博客 1009

Android 怎么就不卡了呢之Choreographer_choreography 安卓(2)

了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

2401_83974590的博客 999

25 - GRACE Mascon数据缺失月份数据插值

本篇基于文章的相关内容和文章公开的奇异谱分析(SSA)插值算法程序包,对grace Mascon数据种缺失的月份进行 插值 ,总结了使用程序包的相关过程,可以将该程序应用到其他数据处理插值计算中。

weixin_43339605的博客 1842

Android 怎么就不卡了呢之Choreographer_choreography 安卓(4)

了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

2401_83974590的博客 677

使用virtuoso gds转lef操作方法

2) 然后,需要创建Pin,这里Pin的概念不同于label/text,是有实际金属的,二者的区别类似于pr中的port和terminal。1) 首先,需要画prBoundary,这个用drawing层的prBoundary画是不行的,不过建议pr阶段就把prBoundary转到gds里,在virtuoso layout中画prBoundary就比较容易。另外,用Create - Create Pin也可以创建pin,更适用于PG pin,操作时先给pg shape打label,最好放正中间。

m0_61544122的博客 1380

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Android 怎么就不卡了呢之Choreographer_choreography 安卓(3)

了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

2401_83974590的博客 641

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

2024年安卓最全Android-怎么就不卡了呢之Choreographer,android常用面试题

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

2401_84557521的博客 422

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Android 怎么就不卡了呢之Choreographer

题外话 时光如斯 人世无常 逼哥忽然就被 全网封杀 难过 还没有去听过现场 总是感觉现在很忙 来日方长 我这种短视动物怎么屑于把意外这种小概率东西纳入考虑范围呢 现在和将来这两个选项悲观点完全能翻译成希望与永别 封杀原因未知 如果是因为XD 这个自媒体猖獗的时代 是个好时代 它把这个世界本有的模样赤裸裸矗在你跟前 允许你怀疑思考进步 也是个坏时代 公信力成了伪命题 把人类最后那点遮羞布撕个...

weixin_34268753的博客 577

最新Android 怎么就不卡了呢之Choreographer_choreography 安卓(1),2024年最新京东面试java

针对Android UI不流畅的问题,Google提出了Project Butter对Android的显示系统进行了重构。这次重构的三个关键点VSynch 垂直同步Triple Buffer 三重缓存Choreographer 编舞者这篇文章我们主要聊一聊Choregrapher,后续的我们写关于其他。对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长。而不成体系的学习效果低效漫长且无助。时间久了,付出巨大的时间成本和努力,没有看到应有的效果,会气馁是再正常不过的。

2401_84544434的博客 414

Android-怎么就不卡了呢之Choreographer,面试android

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。这里只是整理出来的部分面试题,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。)这意味这他有优先执行的权利,他是怎么被优先执行的呢?

2401_84024148的博客 1054
上一篇: Android-开发经验分享:挺重要的网络基础
下一篇: Android-音视频学习系列-(二)-交叉编译动态库、静态库的入门学习
Android_1314
博客等级 码龄5年 1粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值