Android 图形系统之四:Choreographer

news2024/12/27 10:54:51

Choreographer 是 Android 系统中负责帧同步的核心组件,它协调输入事件、动画和绘制任务,以确保界面以固定频率(通常是每 16ms,一帧)流畅渲染。通过管理 VSYNC 信号和调度任务,Choreographer 是实现流畅 UI 体验和高效资源利用的关键。

在这里插入图片描述
图片参考自UI Performance Rendering

以下是系统性的介绍,结合了作用机制、源码解析,以及典型应用场景。

Choreographer 的作用

  1. 帧同步管理 Choreographer 是 UI 渲染任务的中央调度器,负责以帧为单位同步动画和绘制任务,确保它们在 VSYNC 信号到达时运行。
  2. 协调输入、动画和绘制 它按照固定顺序依次处理输入事件、动画逻辑和界面更新,优化任务间的节奏,防止任务冲突或不必要的渲染。
  3. 减少资源浪费 通过将任务与屏幕刷新(VSYNC)同步,避免了无效的重复绘制,节省了 CPU 和 GPU 的资源。

Choreographer 的工作机制

  1. VSYNC 信号监听 系统底层通过 FrameDisplayEventReceiver 捕获 VSYNC 信号,并通知 Choreographer
  2. 回调机制 提供 postFrameCallback 方法,允许开发者将任务加入帧调度队列,任务会在下一帧按需执行。
  3. 帧的分阶段处理 一帧通常分为以下阶段:
    • Input(输入处理):分发触摸、键盘等输入事件。
    • Animation(动画更新):执行动画计算和逻辑。
    • Traversal(界面遍历):触发视图的测量、布局和绘制。
  4. 线程绑定 每个线程有一个独立的 Choreographer 实例,通常主线程上的 Choreographer 是 UI 渲染的核心。

Choreographer 源码解析

以下是 Choreographer 的核心代码和机制分析。

1. 初始化

Choreographer 的构造方法如下:

private Choreographer(Looper looper, int vsyncSource) {
    mLooper = looper;
    mHandler = new FrameHandler(looper);
    mDisplayEventReceiver = new FrameDisplayEventReceiver(looper, vsyncSource);
    mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
    for (int i = 0; i <= CALLBACK_LAST; i++) {
        mCallbackQueues[i] = new CallbackQueue();
    }
}
分析
  • mHandler:基于传入的 Looper 创建,用于任务调度。
  • mDisplayEventReceiver:监听 VSYNC 信号,触发帧更新。
  • mCallbackQueues:维护不同类型的回调队列,如输入、动画和绘制任务。

2. 注册帧回调

开发者可以通过 postFrameCallback 方法注册下一帧需要执行的任务:

public void postFrameCallback(FrameCallback callback) {
    postFrameCallbackDelayed(callback, 0);
}

public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
    long now = SystemClock.uptimeMillis();
    long dueTime = now + delayMillis;
    mCallbackQueues[CALLBACK_ANIMATION].addCallbackLocked(dueTime, callback, null);
    scheduleFrameLocked(now);
}
分析
  • mCallbackQueues 将任务加入 CALLBACK_ANIMATION 队列。
  • scheduleFrameLocked 检查是否需要安排新的帧。

3. VSYNC 信号处理

VSYNC 信号通过 FrameDisplayEventReceiver 捕获,触发帧调度:

@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    Message msg = Message.obtain(mHandler, this::doFrame, timestampNanos);
    msg.setAsynchronous(true);
    mHandler.sendMessageAtTime(msg, timestampNanos / 1000000);
}
分析
  • onVsync 将信号包装成异步消息,通过 Handler 提交到主线程。
  • 消息最终调用 doFrame,启动任务回调。

4. 帧的处理(doFrame)

doFrame 方法负责执行帧内的所有任务回调:

void doFrame(long frameTimeNanos) {
    mFrameScheduled = false;

    doCallbacks(CALLBACK_INPUT, frameTimeNanos);
    doCallbacks(CALLBACK_ANIMATION, frameTimeNanos);
    doCallbacks(CALLBACK_TRAVERSAL, frameTimeNanos);
}
分析
  • doCallbacks 按顺序执行输入、动画、布局绘制任务。
  • 每帧回调在帧时间戳(frameTimeNanos)下运行,确保与屏幕刷新同步。

Choreographer 与其他组件的协作

  1. InputEventReceiver 负责捕获触摸和键盘事件,将输入事件调度到 ChoreographerCALLBACK_INPUT
  2. ViewRootImpl 核心视图管理类,依赖 Choreographer 触发测量、布局和绘制阶段。
  3. 动画系统(ValueAnimator/动画框架) 动画更新依赖 CALLBACK_ANIMATION,确保在 VSYNC 同步时平滑执行。

Choreographer 的应用场景

  1. 实现自定义动画 开发者可以通过 postFrameCallback 在下一帧执行自定义动画逻辑,保持与系统的渲染节奏一致。
choreographer.postFrameCallback(frameTimeNanos -> {
    // 自定义动画逻辑
    choreographer.postFrameCallback(this);
});
  1. 性能优化
  • 使用工具(如 Perfetto)分析帧间隔,定位卡顿原因。
  • 避免阻塞 CALLBACK_TRAVERSAL 队列,提高帧渲染效率。
  1. 任务分阶段调度 在不同阶段安排任务,确保关键操作在合适的时机执行。

总结

Choreographer 是 Android UI 渲染的核心,通过监听 VSYNC 信号和分阶段调度任务,它能够高效管理输入事件、动画和绘制任务,保证帧同步和流畅的用户体验。深入理解其原理和实现,可以帮助开发者优化 UI 性能,设计更高效、更流畅的应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2251497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何构建一个可扩展、全球可访问的 GenAI 架构?

你有没有尝试过使用人工智能生成图像&#xff1f; 如果你尝试过&#xff0c;你就会知道&#xff0c;一张好的图像的关键在于一个详细具体的提示。 我不擅长这种详细的视觉提示&#xff0c;所以我依赖大型语言模型来生成详细的提示&#xff0c;然后使用这些提示来生成出色的图像…

ceph手动部署

ceph手动部署 一、 节点规划 主机名IP地址角色ceph01.example.com172.18.0.10/24mon、mgr、osd、mds、rgwceph02.example.com172.18.0.20/24mon、mgr、osd、mds、rgwceph03.example.com172.18.0.30/24mon、mgr、osd、mds、rgw 操作系统版本&#xff1a; Rocky Linux release …

【iOS】多线程基础

【iOS】多线程基础 文章目录 【iOS】多线程基础前言进程与线程进程进程的状态进程的一个控制结构进程的上下文切换 线程为什么要用线程什么是线程线程和进程的关系线程的上下文切换 线程和进程的优缺点 小结 前言 笔者由于对于GCD不是很了解&#xff0c;导致了项目中网络请求哪…

ArraList和LinkedList区别

文章目录 一、结构不同二、访问速度三、插入和删除操作的不同1、决定效率有两个因素&#xff1a;数据量和位置。2、普遍说法是“LinkedList添加删除快”&#xff0c;这里是有前提条件的 四、内存占用情况五、使用场景六、总结 一、结构不同 LinkedList&#xff1a;它基于双向链…

芯片测试-RF中的S参数,return loss, VSWR,反射系数,插入损耗,隔离度等

RF中的S参数&#xff0c;return loss, VSWR&#xff0c;反射系数&#xff0c;插入损耗&#xff0c;隔离度 &#x1f4a2;S参数&#x1f4a2;&#x1f4a2;S11与return loss&#xff0c;VSWR&#xff0c;反射系数&#x1f4a2;&#x1f4a2;S21&#xff0c;插入损耗和增益&#…

arkTS:持久化储存UI状态的基本用法(PersistentStorage)

arkUI&#xff1a;持久化储存UI状态的基本用法&#xff08;PersistentStorage&#xff09; 1 主要内容说明2 例子2.1 持久化储存UI状态的基本用法&#xff08;PersistentStorage&#xff09;2.1.1 源码1的相关说明2.1.1.1 数据存储2.1.1.2 数据读取2.1.1.3 动态更新2.1.1.4 显示…

《Django 5 By Example》阅读笔记:p455-p492

《Django 5 By Example》学习第 16 天&#xff0c;p455-p492 总结&#xff0c;总计 38 页。 一、技术总结 1.myshop (1)打折功能 使用折扣码实现&#xff0c;但是折扣码是手动生成的&#xff0c;感觉实际业务中应该不是这样的。 (2)推荐功能 使用 Redis 做缓存&#xff0…

深入浅出:开发者如何快速上手Web3生态系统

Web3作为互联网的未来发展方向&#xff0c;正在逐步改变传统互联网架构&#xff0c;推动去中心化技术的发展。对于开发者而言&#xff0c;Web3代表着一个充满机遇与挑战的新领域&#xff0c;学习和掌握Web3的基本技术和工具&#xff0c;将为未来的项目开发提供强大的支持。那么…

otter 高可用策略

关于otter高可用在设计之初&#xff0c;提供了这样几个基本的需求&#xff1a; 1.网络不可靠&#xff0c;异地机房尤为明显. 2.manager/node的jvm不可靠&#xff0c;需要考虑异常crash情况 3.node的jvm不可靠&#xff0c;需要考虑异常crash的情况 4.数据库不可靠&#xff0c;需…

C底层 函数栈帧

文章目录 一&#xff0c;什么是寄存器 二&#xff0c;栈和帧 前言 我们在学习c语言程序的时候&#xff0c;是不是有很多的疑问&#xff0c;如 1&#xff0c;为什么形参不可以改变实参 2&#xff0c;为什么我们编写程序的时候会出现烫烫烫......这个乱码 3&#xff0c;那些局…

力扣1382:将二叉搜索树便平衡

给你一棵二叉搜索树&#xff0c;请你返回一棵 平衡后 的二叉搜索树&#xff0c;新生成的树应该与原来的树有着相同的节点值。如果有多种构造方法&#xff0c;请你返回任意一种。 如果一棵二叉搜索树中&#xff0c;每个节点的两棵子树高度差不超过 1 &#xff0c;我们就称这棵二…

亚马逊自研大语言模型 Olympus 即将亮相,或将在 LLM 竞赛中掀起新波澜

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

指针与引用错题汇总

int *p[3]; // 定义一个包含 3 个指向 int 的指针的数组int a 10, b 20, c 30; p[0] &a; // p[0] 指向 a p[1] &b; // p[1] 指向 b p[2] &c; // p[2] 指向 c // 访问指针所指向的值 printf("%d %d %d\n", *p[0], *p[1], *p[2]); // 输出: 10 20 30…

vscode ctrl+/注释不了css

方式一.全部禁用插件排查问题. 方式二.打开首选项的json文件,注释掉setting.json,排查是哪一行配置有问题. 我的最终问题:需要将 "*.vue": "vue",改成"*.vue": "html", "files.associations": { // "*.vue": &qu…

医疗知识图谱的问答系统详解

一、项目介绍 该项目的数据来自垂直类医疗网站寻医问药&#xff0c;使用爬虫脚本data_spider.py&#xff0c;以结构化数据为主&#xff0c;构建了以疾病为中心的医疗知识图谱&#xff0c;实体规模4.4万&#xff0c;实体关系规模30万。schema的设计根据所采集的结构化数据生成&…

上传镜像docker hub登不上和docker desktop的etx4.vhdx占用空间很大等解决办法

平时使用docker一般都在Linux服务器上&#xff0c;但这次需要将镜像上传到docker hub上&#xff0c;但是服务器上一直无法登录本人的账号&#xff0c;&#xff08;这里的问题应该docker 网络配置中没有开代理的问题&#xff0c;因服务器上有其他用户使用&#xff0c;不可能直接…

大型复杂项目管理怎么结合传统与敏捷

大型复杂项目管理需要综合运用传统的瀑布模型与敏捷方法&#xff0c;两者各具优势&#xff0c;可以在不同的项目阶段和需求下发挥最大效能。首先&#xff0c;在项目的初期阶段&#xff0c;传统方法的详细规划和需求分析能够帮助确保项目方向正确、资源充足&#xff1b;敏捷方法…

PVE中VLAN的设置要点

使用这个拓扑进行连接无法直接访问PVE PVE 设置如下&#xff1a; 核心重点&#xff1a;PVE 的 vmbr0 接口直接绑定了 enp2s0&#xff0c;这会导致 VLAN 流量无法正确处理&#xff0c;因为 PVE 没有专门为 VLAN 3 配置接口。 1.vmbr0 和 vmbr0.3 都是绑定在物理接口 enp2s0 上&…

网络安全防范技术

1 实践内容 1.1 安全防范 为了保障"信息安全金三角"的CIA属性、即机密性、完整性、可用性&#xff0c;信息安全领域提出了一系列安全模型。其中动态可适应网络安全模型基于闭环控制理论&#xff0c;典型的有PDR和P^2DR模型。 1.1.1 PDR模型 信息系统的防御机制能抵抗…

.net —— Razor

文章目录 项目地址一、创建一个Razor项目1.1 创建项目1.2 创建项目所需文件夹1.3 配置项目二、创建Category页面2.1 创建Category的展示页面2.2 增删改2.2.1 创建Edit的razor视图项目地址 教程作者:教程地址:代码仓库地址:所用到的框架和插件:dbt airflow一、创建一个Razo…