《高性能鸿蒙应用开发实践解析-王雷.pdf》由会员分享,可在线阅读,更多相关《高性能鸿蒙应用开发实践解析-王雷.pdf(28页珍藏版)》请在三个皮匠报告上搜索。
1、高性能鸿蒙应用开发分享人:鸿蒙ArkUI框架技术专家 王雷鸿蒙应用构成鸿蒙应用构成构成构成Stage模型模型应用组件1.组件分类stage-model-component -UIAbility组件:包含UI,提供展示UI的能力,主要用于和用户交互。详细介绍请参见UIAbility组件概述。-ExtensionAbility组件:提供特定场景(如卡片、输入法)的扩展能力,满足更多的使用场景。详细介绍请参见ExtensionAbility组件概述。2.开发方式 采用面向对象的方式,将应用组件以类接口的形式开放给开发者,可以进行派生,利于扩展能力。进程模型1.主进程2.ExtensionAbilit
2、y进程3.渲染进程线程模型1.ArkTS引擎实例的创建 一个进程可以运行多个应用组件实例,所有应用组件实例共享一个ArkTS引擎实例。2.线程模型 ArkTS引擎实例在主线程上创建。3.进程内对象共享:支持。任务管理模型 每个UIAbility组件实例创建一个任务。-任务会持久化存储,直到超过最大任务个数(根据产品配置自定义)或者用户主动删除任务。-UIAbility组件之间不会形成栈的结构。配置文件使用app.json5描述应用信息,module.json5描述HAP信息、应用组件信息。Stage ModeUIAbilityServiceExtensionAbilityExtensionAb
3、ility.InputMethodExtensionAbilityDataShareExtensionAbilityDriverExtensionAbility性能影响性能影响纬度纬度 语言纬度:ArkTS 线程模型:Worker&TaskPool UI构成:ArkUI框架 图形渲染:ArkGraphics渲染引擎 分析工具ArkTSArkTS语言语言特性特性高性能容器类库高性能容器类库线性线性容器容器非线性非线性容器容器ArrayListHashMapVectorHashSetListTreeMapLinkedListTreeSetDequeLightWeightMapQueueLightW
4、eightSetStackPlainArrayimport ArrayList from ohos.util.XXX;ArkTS语言使用过程中性能提升语言使用过程中性能提升方法方法 热点循环中常量提取,减少属性访问次数 避免频繁使用delete 数值计算避免溢出 避免使用稀疏数组 使用字面量进行对象创建 避免动态添加属性 避免使用type类型标注 声明参数要和实际的参数一致 避免动态声明function与class了解启动流程各阶段执行内容,合理配置应用了解启动流程各阶段执行内容,合理配置应用结构,提升启动结构,提升启动速度速度合理配置启动页面图标尺寸,减少解码开销合理配置启动页面图标尺寸,减
5、少解码开销 abilities:name:EntryAbility,srcEntrance:./ets/entryability/EntryAbility.ts,description:$string:EntryAbility_desc,icon:$media:icon,label:$string:EntryAbility_label,startWindowIcon:$media:startWindowIcon,/在这里修改启动页图标,建议不要超过256像素x256像素 startWindowBackground:$color:start_window_background,visible:t
6、rue,skills:entities:entity.system.home ,actions:action.system.home 按需引入模块,合理使用生命周期,避免按需引入模块,合理使用生命周期,避免耗时耗时操作操作上海品茶组件按需创建,页面生命周期避免耗上海品茶组件按需创建,页面生命周期避免耗时时操作操作使用异步机制,降低使用异步机制,降低UIUI线程同步线程同步操作负载操作负载组件中的异步组件中的异步逻辑逻辑T Ta as sk kP Po oo ol l机机制制wwo or rk ke er r机机制制Image解码器UI ThreadBackground Thread共享内存 Pixel
7、Map应用异步应用异步机制机制UIUI框架运行流程与性能影响框架运行流程与性能影响点点应用组件树应用组件树阶段阶段1:1:数据数据处理处理阶段阶段2:UI2:UI更新更新状态数据更新(应用)UI数据更新(框架)BuildMeasureLayoutRender脏节点脏节点列表列表性能影响点:性能影响点:状态数据更新数量 更新脏组件数量开发开发约束:约束:布局约束 状态更新约束 懒加载更新约束性能影响点:性能影响点:组件创建数量 属性更新数量 布局更新范围 绘制指令数量开发开发约束:约束:布局合理使用 组件复用,避免重复创建UIUI框架运行流程:数据处理框架运行流程:数据处理流程流程开发者视角开发
8、者视角EntryComponentstruct Index State message:string=Hello World build()Row()Column()Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).width(100%).onClick()=this.message=Hello ArkUI ).height(100%)依赖收集过程依赖收集过程build执行get:this.messge get()this.notifyPropertyHasBeenReadPU();return this.wrappedVa
9、lue_;记录Text emId,建立组件&数据关联关系存入状态数据内部Set完成数据依赖收集recordDependentUpdate()const elmtId=ViewStackProcessor.GetElmtIdToAccountFor();if(elmtId ViewStackProcessor.StartGetAccessRecordingFor(elmtId);Text.create(this.message);Text.fontSize(50);Text.fontWeight(FontWeight.Bold);if(!isInitialRender)Text.pop();Vi
10、ewStackProcessor.StopGetAccessRecording(););刷新UI属性渲染树置脏绘制脏 or 布局脏FrameFrameNodeTreeNodeTree布局边界布局脏绘制脏RowTextTextUIUI框架运行流程:框架运行流程:UIUI更新流程更新流程FrameFrameNodeTreeNodeTree布局边界布局脏绘制脏布局布局过程过程查询脏节点数组获取脏节点对象measure递归遍历children,进行measure布局参数未变化跳过Layoutmeasure 完成后,进入layout流程自底向上进行排布像素对齐绘制脏不一定触发布局更新,布局脏一定触发布局
11、更新和绘制更新绘制绘制过程过程遍历脏组件生成绘制指令指令下发状态管理合理使用,精准控制组件更新状态管理合理使用,精准控制组件更新范围范围常见冗余刷新常见:大数据对象关联组件过多,造成刷新范围常见冗余刷新常见:大数据对象关联组件过多,造成刷新范围大大Observedclass UIStyle translateX:number=0;translateY:number=0;scaleX:number=0.3;scaleY:number=0.3;width:number=336;height:number=178;posX:number=10;posY:number=50;alpha:number=
12、0.5;borderRadius:number=24;imageWidth:number=78;imageHeight:number=78;translateImageX:number=0;translateImageY:number=0;fontSize:number=20;同一数据对象中,不同属性被多个组件所使用,同一数据对象中,不同属性被多个组件所使用,当数据对象任一属性值发生变化时,所有绑定当数据对象任一属性值发生变化时,所有绑定该对象的组件都被标记为脏,发生该对象的组件都被标记为脏,发生刷新刷新Component1UIStyle.translateXUIStyle.translate
13、YComponent2UIStyle.scaleXUIStyle.scaleYComponent3UIStyle.fontSize状态管理合理使用,精准控制组件更新状态管理合理使用,精准控制组件更新范围范围通过通过Observed装饰器,进行数据合理拆分,实现更新范围最小装饰器,进行数据合理拆分,实现更新范围最小化化Component1UIStyle.needRenderTranslateComponent2UIStyle.needRenderscaleComponent3UIStyle.needRenderFontSizeObservedclass NeedRenderTranslate p
14、ublic translateImageX:number=0;public translateImageY:number=0;Observedclass NeedRenderScale public scaleX:number=0.3;public scaleY:number=0.3;Observedclass NeedRenderFontSize public fontSize:number=20;Observedclass NeedRenderOthers /properties usually used together can be divided into the same new
15、divided class /。Observedclass UIStyle needRenderTranslate:NeedRenderTranslate=new NeedRenderTranslate();needRenderFontSize:NeedRenderFontSize=new NeedRenderFontSize();needRenderScale:NeedRenderScale=new NeedRenderScale();/。使用懒加载技术,控制列表更新范围,避免超长列表更新使用懒加载技术,控制列表更新范围,避免超长列表更新阻塞阻塞List 列表组件ForEach数据管理器数据
16、源一次性读取全部数据,耗时长适用于列表项数量不多或只有1屏数据场景,当列表项数量大时,会造成加载耗时阻塞使用懒加载能力,按需读取数据List 列表组件LazyForEach数据管理器数据源滚动过程中进行数据读取和加载Item1Item2Item3Item4Item5Item6Item7Item8Item1Item2Item3Item4Item5Item6Item7Item8组件复用机制,减少组件创建组件复用机制,减少组件创建List 列表组件Item1Item2Item3Item4Item5Item6Item7Item8组件复用池摘除进入组件复用池不进行销毁Item0从组件复用池中获取组件不进
17、行创建LazyForEach(this.GoodDataOne,(item,index)=GridItem()GoodItems(img:item.data.img,webimg:item.data.webimg,hei:item.data.hei,).reuseId(this.CombineStr(item.type),(item)=JSON.stringify(item)ReusableComponentstruct GoodItems State img:Resource=$r(app.media.photo61)State webimg?:string=State hei:number
18、=0 LocalStorageLink(storageSimpleProp)simpleVarName:string=boo:boolean=true index:number=0 controllerVideo:VideoController=new VideoController();aboutToReuse(params)this.webimg=params.webimg this.img=params.img this.hei=params.hei build()/.懒加载机制与组件复用机制在组件中的使用懒加载机制与组件复用机制在组件中的使用瀑布流瀑布流布局布局 build()Colu
19、mn(space:2)WaterFlow()LazyForEach(this.datasource,(item:number)=FlowItem()Column()Text(N+item).fontSize(12).height(16)Image(res/waterFlowTest(+item%5+).jpg).objectFit(ImageFit.Fill).width(100%).layoutWeight(1).width(100%)/提前设定FlowItem高度,避免自适应图片高度 .height(this.itemHeightArrayitem).backgroundColor(thi
20、s.colorsitem%5),(item:string)=item).columnsTemplate(1fr1fr).columnsGap(10).rowsGap(5).backgroundColor(0 xFAEEE0).width(100%).height(80%)效果展示效果展示懒加载能力与懒加载能力与WaterFlowWaterFlow组合组合使用使用 build()Column(space:2)WaterFlow()LazyForEach(this.datasource,(item:number)=FlowItem()Column()Text(N+item).fontSize(12
21、).height(16)Image(res/waterFlowTest(+item%5+).jpg).objectFit(ImageFit.Fill).width(100%).layoutWeight(1).onAppear()=/即将触底时提前增加数据 if(item+20=this.datasource.totalCount()for(let i=0;i item)懒加载能力实现无限懒加载能力实现无限滚动滚动懒加载机制与组件复用机制在组件中的使用懒加载机制与组件复用机制在组件中的使用瀑布流瀑布流布局布局懒加载能力结合组件复用机制,达到最佳滚动性能懒加载能力结合组件复用机制,达到最佳滚动性能
22、体验体验 build()Column(space:2)WaterFlow()LazyForEach(this.datasource,(item:number)=FlowItem()/使用可复用自定义组件 ResuableFlowItem(item:item).onAppear()=/即将触底时提前增加数据 if(item+20=this.datasource.totalCount()for(let i=0;i item).columnsTemplate(1fr1fr).columnsGap(10).rowsGap(5).backgroundColor(0 xFAEEE0).width(100%
23、).height(80%)ReusableComponentstruct ResuableFlowItem State item:number=0 /从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 aboutToReuse(params)this.item=params.item;build()Column()Text(N+this.item).fontSize(12).height(16)Image(res/waterFlowTest(+this.item%5+).jpg).objectFit(ImageFit.Fill).width(100%).layoutW
24、eight(1)懒加载机制与组件预懒加载机制与组件预加载机制在组件中的使用加载机制在组件中的使用页面页面滑动滑动翻页效果展示翻页效果展示当页面较多数量大时,一次性创建全部页面显然并不划算优化机制:利用滑动过程动画时间,并行进行页面创建 控制加载的页面数量通过通过cacheCountcacheCount设置预加载设置预加载页面数量页面数量滑动动画滑动动画&页面创建页面创建并行并行UI线程RS线程跟手滑动切换动画执行加载下一页面优化页面布局,高效组织优化页面布局,高效组织UIUI结构结构合理使用布局,降低合理使用布局,降低UIUI层级层级 归并相同类型布局,避免冗余组件使用选用扁平选用扁平化布局,
25、降低化布局,降低UIUI层级层级 使用使用属性动画属性动画能力,避免帧动画占用能力,避免帧动画占用UIUI线程线程传统动画传统动画处理过程处理过程vsync信号动画插值计算组件属性更新布局计算绘制指令生成刷新当前帧鸿蒙动画鸿蒙动画处理过程处理过程vsync信号更新状态数据计算最终位置配置动画参数发送指令执行动画vsync信号动画插值绘制UI线程UI线程动画线程动画使用动画使用示例示例 State textScaleX:number=1;State textScaleY:number=1;Text().backgroundColor(Color.Blue).fontColor(Color.Whi
26、te).fontSize(20).width(10).height(10).scale(x:this.textScaleX,y:this.textScaleY).margin(top:100)Button(图形变换属性).onClick()=animateTo(duration:1000,()=this.textScaleX=10;this.textScaleY=10;)通过节点组缓存(通过节点组缓存(renderGrouprenderGroup),提升渲染),提升渲染性能性能1组件渲染顺序组件渲染顺序234512345按按Z Z序自底向上逐层绘制序自底向上逐层绘制节点组缓存,一次性节点组缓存
27、,一次性绘制绘制1234512345首次首次绘制:按绘制:按Z Z序自底向上逐层绘制序自底向上逐层绘制缓存绘制纹理发生重绘读取纹理,直接绘制通过节点组缓存(通过节点组缓存(renderGrouprenderGroup),提升渲染),提升渲染性能性能组组件件渲渲染染流流程程合理使用节点组缓存,平衡性能合理使用节点组缓存,平衡性能&内存内存缓存更新缓存更新条件:条件:组件在当前组件树上 组件renderGroup被标记为true 组件内容被标脏缓存清理缓存清理条件:条件:组件不存在于组件树上 组件renderGroup被标记为false适用场景适用场景 组件内容固定不变组件内容固定不变&内部无内部
28、无动效动效组件内容固定不变或更新频率低,会加大缓存的使用率,减少缓存组件内容固定不变或更新频率低,会加大缓存的使用率,减少缓存更新增加的开销更新增加的开销 执行动画的过程执行动画的过程执行动画过程中内容通常没有变化,此时在动画执行前将动画目标执行动画过程中内容通常没有变化,此时在动画执行前将动画目标组件标记为节点组,可提升动画帧率,动画结束后,恢复原始状态组件标记为节点组,可提升动画帧率,动画结束后,恢复原始状态探索中的性能提升探索中的性能提升思路思路组件预创建能力利用UI线程空闲时间,提前准备数据动画配置动画执行动画结束回调组件创建属性更新布局计算绘制提交渲染密集计算空闲时间动画配置动画执行
29、动画结束回调属性设置布局计算组件挂树绘制提交渲染局部更新效率更高组件预创建属性更新布局更新应用性能分析工具应用性能分析工具CPU ProfilerCPU Profiler:查看:查看ArkTSArkTS耗时耗时分析分析HiDumperHiDumper命令行工具:查看命令行工具:查看UIUI结构结构 开启ArkUI的debug模式:hdc shell param set persist.ace.debug.enabled 1 重新启动应用 获取当前页面对应应用的window ID:hdc shell hidumper-s WindowManagerService-a-a 通过WinId获取对应页
30、面的控件树文件:hdc shell hidumper-s WindowManagerService-a-w 28-element-c 查看 arkui.dump 文件探索中的性能提升探索中的性能提升思路思路多线程离屏绘制:并行绘制,UI线程显示纹理渲染线程UI线程后台线程1后台线程2绘制任务1绘制任务2Create OffscreenCanvasDraw PixelMapPost MessageCreate OffscreenCanvasDraw PixelMapPost Message收集绘制结果共享内存PixelMap1PixelMap2绘制纹理UI更新HiDumperHiDumper命令
31、行工具:查看命令行工具:查看UIUI结构结构/arkui.dump文件内容片断|-GridItem childSize:1|ID:22|Depth:9|IsDisappearing:0|FrameRect:RectT(360.00,0.00)-180.00 x 29.00|BackgroundColor:#00000000 .|-Stack childSize:1|ID:23|Depth:10|IsDisappearing:0|FrameRect:RectT(0.00,0.00)-180.00 x 29.00|BackgroundColor:#FFFFFF00 .|-Stack childSi
32、ze:1|ID:24|Depth:11|IsDisappearing:0|FrameRect:RectT(0.00,0.00)-180.00 x 29.00|BackgroundColor:#FF0000FF .|-Stack childSize:1|ID:25|Depth:12|IsDisappearing:0|FrameRect:RectT(0.00,0.00)-180.00 x 29.00|BackgroundColor:#00000000 .|-Text childSize:0 ID:26 Depth:13 IsDisappearing:0 FrameRect:RectT(83.00,
33、0.00)-14.00 x 29.00 BackgroundColor:#00000000 .字段说明childSize:组件内子组件数量ID:当前组件的ID值,此ID非应用设置,而是自增累加Depth:当前组件在UI Tree中深度IsDisappearing:显示状态FrameRect:组件尺寸Background:组件背景色其他:各组件渲染属性都可查看 SmartPerf-HostSmartPerf-Host工具分析应用性能工具分析应用性能配置SmartPerf参数分析UI数据帧率数据线程Trace耗时分析ArkUI-X ArkUI-X 跨平台项目期待您的加入跨平台项目期待您的加入共建共建https:/