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

📅 2026/7/14 0:59:18
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等技术优化绘制指令进一步提升流畅度。