HarmonyOS APP实战-画图APP - 第14篇:可变帧率与性能优化

发布时间:2026/9/12 18:15:57

HarmonyOS APP实战-画图APP - 第14篇:可变帧率与性能优化 HarmonyOS APP实战-画图APP - 第14篇使用displaySync定制绘制帧率开篇上一篇我们完成了本地数据库存储与读取功能通过关系型数据库RdbStore保存了画作元数据名称、创建时间、缩略图路径并实现了画作列表页面支持从列表加载已有画作继续编辑。数据库模块是画图APP的数据持久化基石。本篇将聚焦性能优化——根据绘制内容的复杂度动态调整绘制帧率。画图APP在画笔手绘时需要高帧率60fps保证跟手性而空闲状态或显示静态图形时可以降低帧率至30fps以减少功耗。HarmonyOS提供了displaySyncAPI允许开发者针对自绘制内容指定不同的目标帧率。我们将封装一个FrameRateController模块并在DrawingCanvas组件中集成它实现按需切换帧率。核心实现基础配置导入与常量定义首先在模块顶部导入displaySync并定义帧率常量。// FrameRateController.etsimport{displaySync}fromohos.graphics.displaySync;/** * 帧率常量 */exportconstFRAME_RATE_HIGH60;// 高帧率模式画笔绘制时exportconstFRAME_RATE_LOW30;// 低帧率模式静止或浏览时关键点说明ohos.graphics.displaySync是ArkGraphics 2D提供的可变帧率能力模块。帧率值单位是fps帧每秒60fps适合手绘追踪30fps满足静态显示且降低功耗。核心逻辑FrameRateController类FrameRateController负责创建和管理DisplaySync实例并根据业务状态设置目标帧率。// FrameRateController.etsexportclassFrameRateController{privatedisplaySyncInstance:displaySync.DisplaySync|nullnull;privateisRunning:booleanfalse;privatecurrentRate:numberFRAME_RATE_LOW;/** * 初始化DisplaySync实例 * param requestId 请求标识用于区分不同绘制场景 */publicasyncinit(requestId:string):Promisevoid{if(this.displaySyncInstance){return;}try{this.displaySyncInstanceawaitdisplaySync.create(requestId);console.info(FrameRateController: DisplaySync created with requestId${requestId});}catch(err){console.error(FrameRateController: create failed, error${JSON.stringify(err)});}}/** * 启动帧率控制 * param frameCallback 每帧回调参数为时间戳 */publicstart(frameCallback:(timestamp:number)void):void{if(!this.displaySyncInstance||this.isRunning){return;}this.displaySyncInstance.start(frameCallback);this.isRunningtrue;console.info(FrameRateController: started);}/** * 停止帧率控制 */publicstop():void{if(!this.displaySyncInstance||!this.isRunning){return;}this.displaySyncInstance.stop();this.isRunningfalse;console.info(FrameRateController: stopped);}/** * 更新目标帧率 * param rate 新的帧率值fps */publicupdateFrameRate(rate:number):void{if(!this.displaySyncInstance){console.warn(FrameRateController: instance not initialized);return;}try{this.displaySyncInstance.setExpectedFrameRate(rate);this.currentRaterate;console.info(FrameRateController: frame rate updated to${rate}fps);}catch(err){console.error(FrameRateController: setExpectedFrameRate failed, error${JSON.stringify(err)});}}/** * 销毁DisplaySync实例 */publicdestroy():void{if(this.displaySyncInstance){this.displaySyncInstance.destroy();this.displaySyncInstancenull;this.isRunningfalse;console.info(FrameRateController: destroyed);}}/** * 获取当前帧率 */publicgetCurrentRate():number{returnthis.currentRate;}}关键点说明displaySync.create(requestId)是一个异步方法返回PromiseDisplaySync实例。setExpectedFrameRate(rate)设置期望帧率系统会尽量按照该值调度。start(callback)开始帧率控制回调参数为时间戳纳秒可用于驱动动画循环。destroy()释放资源在页面销毁时调用。实际项目中帧率回调可以作为绘制驱动的定时器替代setInterval或requestAnimationFrame提供更精确的帧同步。完整模块集成到DrawingCanvas组件DrawingCanvas是画图APP的核心绘制组件。我们在其中集成FrameRateController在触摸开始/移动时切换到高帧率触摸结束或闲置时降回低帧率。同时为了兼容原有绘制逻辑我们将帧率回调绑定到画布重绘操作。// DrawingCanvas.ets简化版仅展示集成逻辑import{CanvasRenderingContext2D}fromohos.graphics.ui;import{FrameRateController,FRAME_RATE_HIGH,FRAME_RATE_LOW}from./FrameRateController;import{Point,DrawCommand}from../model/DrawCommand;// 假设自定义模型Componentexportstruct DrawingCanvas{privatesettings:RenderingContextSettingsnewRenderingContextSettings(true);privatecontext:CanvasRenderingContext2DnewCanvasRenderingContext2D(this.settings);privateframeCtrl:FrameRateControllernewFrameRateController();privateisDrawing:booleanfalse;privatelastTouch:Point{x:0,y:0};// ... 其他属性aboutToAppear(){// 初始化DisplaySyncrequestId可自定义this.frameCtrl.init(drawing_canvas_main).then((){// 启动帧率控制将回调连接到画布刷新this.frameCtrl.start((timestamp:number){// 这里可以驱动持续的绘制更新例如动画// 对于手绘我们只在触摸事件中局部重绘此回调暂不开启批量重绘// 但保持帧率控制活跃});// 初始设为低帧率this.frameCtrl.updateFrameRate(FRAME_RATE_LOW);});}onTouch(event:TouchEvent){if(!this.frameCtrl)return;switch(event.type){caseTouchType.Down:this.isDrawingtrue;// 触摸开始时切换到高帧率保证跟手this.frameCtrl.updateFrameRate(FRAME_RATE_HIGH);this.lastTouch.xevent.touches[0].x;this.lastTouch.yevent.touches[0].y;// 开始新路径this.startNewPath(this.lastTouch);break;caseTouchType.Move:if(this.isDrawing){constcurrent{x:event.touches[0].x,y:event.touches[0].y};// 添加点到当前路径并绘制this.addPointToPath(current);this.lastTouchcurrent;}break;caseTouchType.Up:caseTouchType.Cancel:// 绘制结束恢复低帧率if(this.isDrawing){this.finishPath();this.isDrawingfalse;this.frameCtrl.updateFrameRate(FRAME_RATE_LOW);}break;}}privatestartNewPath(point:Point):void{// 原有逻辑开始一个新的Path}privateaddPointToPath(point:Point):void{// 原有逻辑向Path增加点并调用context.drawPath()}privatefinishPath():void{// 原有逻辑结束路径并保存到历史}aboutToDisappear(){this.frameCtrl.stop();this.frameCtrl.destroy();}build(){Canvas(this.context).width(100%).height(100%).onTouch((event:TouchEvent)this.onTouch(event))}}议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_urlplaceholder.pngpos_idimg-K54aM3fo-1783906018434)关键点说明aboutToAppear中初始化FrameRateController并启动默认低帧率。在onTouch的Down事件中更新为高帧率Up或Cancel时恢复低帧率。注意帧率回调本身不涉及重绘但保持start可以让系统按照目标帧率调度实际绘制仍由触摸事件触发。aboutToDisappear中停止并销毁实例防止内存泄漏。如果后续需要实现动画绘制如动态渐变、粒子效果可以利用frameCallback的时间戳驱动逐帧重绘此时帧率控制效益更明显。运行验证在画图APP中打开任意画布文件或新建画布用手指在画布上绘制当手指按下并移动时CPU/GPU会按60fps渲染轨迹体验流畅跟手。当手指抬起后帧率会降为30fps此时进行菜单操作或查看静态内容手机功耗降低。开发者可以通过DevEco Studio的Profiler工具查看帧率变化运行APP点击“性能分析”在“帧率时间线”中观察绘制时段帧率约60fps闲置时段约30fps。如果未看到切换请确认displaySync已正确初始化和权限设置无需额外权限。另外模拟器可能不完全支持帧率动态调节建议在真机上测试。小结与预告本篇实现了画图APP的帧率动态调节功能通过FrameRateController模块封装displaySyncAPI根据绘制活动自动切换60fps和30fps在保持手绘跟手性的同时减少闲置功耗。该模块是性能优化的重要一环可直接复用至其他自绘制场景。下一篇《使用overdraw工具检测性能》将介绍如何利用HarmonyOS的过度绘制调试工具Overdraw Debug分析画布绘制效率识别冗余绘制层次并通过Canvas的clip、clearRect等技术优化绘制指令进一步提升流畅度。
延伸阅读

更多相关文章

2026/9/10 22:33:34

HarmonyOS APP实战-画图APP - 第12篇:离线图像处理与保存

HarmonyOS APP实战-画图APP - 第12篇&#xff1a;导出与加载图片文件 1. 开篇 上一篇我们完成了操作历史管理模块&#xff0c;实现了基于命令模式的撤销/重做栈&#xff1a;HistoryManager 类维护了两个 Stack<Command> 实例&#xff0c;每次绘制操作封装为 Command 对象…

2026/9/10 13:12:10

2026年多商户商城系统哪个好?商家入驻、分账和权限对比

2026年多商户商城系统哪个好&#xff1f;商家入驻、分账和权限对比多商户商城系统哪个好&#xff0c;不能只看能不能上架商品。平台型业务和单店商城不一样&#xff0c;核心在商家能不能入驻&#xff0c;平台能不能审核商品&#xff0c;订单和售后责任怎么划分&#xff0c;平台…

2026/9/12 8:27:14

育儿专题(3)疫苗

目录 1&#xff0c;国家免疫规划疫苗儿童免疫程序表 2&#xff0c;详细疫苗规划 &#xff08;0&#xff09;背景&#xff08;必读&#xff09; &#xff08;1&#xff09;卡介苗&#xff08;出生&#xff09; &#xff08;2&#xff09;甲肝、乙肝、2联&#xff08;出生、…

2026/9/12 18:10:57

STM32学习(五)—— 时钟体系

一、什么是晶振晶振的全称叫做晶体振荡器&#xff0c;是晶体&#xff08;石英&#xff09;和电子元件组成&#xff0c;晶振有一个非常重要的特性&#xff1a;机电效应&#xff08;压电效应&#xff09;&#xff0c;一般晶振会提供高度稳定的频率&#xff08;振荡频率是固定的&a…

2026/9/12 18:10:57

ABAQUS随机颗粒生成器:Python脚本实现二维非重叠颗粒建模

简介&#xff1a;这是一套基于ABAQUS的二维随机颗粒生成插件&#xff0c;面向从事颗粒材料有限元模拟的工程师与科研人员。核心功能通过Python脚本调用ABAQUS内建函数&#xff0c;自动完成颗粒尺寸、形状、材料属性及分布区域的参数化设置&#xff0c;并借助随机数算法生成位置…

2026/9/12 18:10:57

SpringBoot+JSP网络订餐系统:工程构建与并发事务处理

简介&#xff1a;这是一份基于 Spring Boot 与 JSP 技术栈的 Java 网络订餐系统设计源码&#xff0c;面向 Java Web 开发者、毕业设计及课程设计人群&#xff0c;能够帮助读者快速掌握 Spring Boot 框架与 JSP 动态页面、数据库集成的完整项目开发流程。压缩包共 169 个文件、约…

2026/9/12 18:10:57

国资:高管退休潮背后的深层逻辑与组织进化

《央企换帅&#xff0c;看名单的人都看错了》 ——升迁只改座位&#xff0c;退休才改规则一天之内&#xff0c;十七家中央企业、二十三名高管变动&#xff0c;其中十六人的结局是同一个词&#xff1a;退休。名单一出&#xff0c;大家下意识找“谁上去了”。可这份公告真正完成的…

2026/9/12 18:10:57

Python属性装饰器:数据封装与访问控制实战

1. 为什么需要属性装饰器&#xff1a;从数据失控到优雅封装在Python面向对象编程中&#xff0c;我们经常遇到一个经典矛盾&#xff1a;直接暴露实例属性虽然简单方便&#xff0c;但无法对赋值进行有效控制。想象你正在开发学生成绩管理系统&#xff0c;如果允许直接修改score属…

2026/9/12 18:05:57

牡丹芍药春季养护:抹芽疏蕾技巧与时机把握

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊&#xff01;#雷神 #复联”这类调侃式短标题&#xff0c;第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里&#xff0c;但细想一下就能发现&#xff0c;它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊&#xff0c;可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”&#xff0c;你会发现&#xff0c;这场比较本质上是两个不同 IP 策略的长期结果对比&#xff1a;超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介&#xff1a;本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案&#xff0c;聚焦调制信号自动检测与识别这一典型无线通信任务&#xff0c;解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件&#xff08;10.73MB&#xff09;&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介&#xff1a;本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包&#xff0c;聚焦于长鼻浣熊优化算法&#xff08;COA&#xff09;的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题&#xff0c;作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码