欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 【鸿蒙应用开发】性能优化

【鸿蒙应用开发】性能优化

2025/2/28 10:13:28 来源:https://blog.csdn.net/u010253415/article/details/145837249  浏览:    关键词:【鸿蒙应用开发】性能优化

渲染方面

Repeat:可复用的循环渲染

Repeat 一般会用于取代 ForEach,相较后者具有更强的渲染性能,Repeat 具有两种工作模式:

non-virtualScroll 模式

在初始化页面时就加载列表中的全部子组件。

相比于ForEach,具有一定的性能优化,一方面针对数据的更新性能进行了优化,其次是生成函数中的索引管理转移到了框架层。

virtualScroll 模式

需要开启 virtualScroll 开关,它属于动态加载机制,通过可视区域 + 预加载区域来加载子组件,当你的容器滑动或者数组元素改变时,它会重新计算加载返回,帮助你管理节点的创建和销毁。

适合场景

懒加载长数据列表,希望通过组件复用来优化性能表现的场景。

示例代码
// 在List容器组件中使用Repeat virtualScroll模式
@Entry
@ComponentV2 // 推荐使用V2装饰器
struct RepeatExample {@Local dataArr: Array<string> = []; // 数据源aboutToAppear(): void {for (let i = 0; i < 50; i++) {this.dataArr.push(`data_${i}`); // 为数组添加一些数据}}build() {Column() {List() {Repeat<string>(this.dataArr).each((ri: RepeatItem<string>) => { // 默认模板ListItem() {Text('each_A_' + ri.item).fontSize(30).fontColor(Color.Red) // 文本颜色为红色}}).key((item: string, index: number): string => item) // 键值生成函数.virtualScroll({ totalCount: this.dataArr.length }) // 打开virtualScroll模式,totalCount 为期望加载的数据长度}.cachedCount(2) // 容器组件的预加载区域大小.height('70%').border({ width: 1 }) // 边框}}
}

Repeat:可复用的循环渲染https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-new-rendering-control-repeat-V5

LazyForEach:数据懒加载

按需加载迭代数据,框架根据滚动容器的可视范围来按需创建组件,当组件滑出可视区域外时,框架会销毁部分组件来降低内存占用。

首次渲染

首次渲染时,根据键值生成规则为数据源的每个数组元素生成唯一键值,并创建组件。

/** BasicDataSource代码见文档末尾附件: string类型数组的BasicDataSource代码 **/class MyDataSource extends BasicDataSource {private dataArray: string[] = [];public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i <= 20; i++) {this.data.pushData(`Hello ${i}`)}}build() {List({ space: 3 }) {LazyForEach(this.data, (item: string) => {ListItem() {Row() {Text(item).fontSize(50).onAppear(() => {console.info("appear:" + item)})}.margin({ left: 10, right: 10 })}}, (item: string) => item)}.cachedCount(5)}
}
非首次渲染

当数据发生变化,再次引发渲染时,应正确处理和调用对应的接口(通知LazyForEach更新),以下是当数据源内新增数据时的处理。

/** BasicDataSource代码见文档末尾附件: string类型数组的BasicDataSource代码 **/class MyDataSource extends BasicDataSource {private dataArray: string[] = [];public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i <= 20; i++) {this.data.pushData(`Hello ${i}`)}}build() {List({ space: 3 }) {LazyForEach(this.data, (item: string) => {ListItem() {Row() {Text(item).fontSize(50).onAppear(() => {console.info("appear:" + item)})}.margin({ left: 10, right: 10 })}.onClick(() => {// 点击追加子组件this.data.pushData(`Hello ${this.data.totalCount()}`);})}, (item: string) => item)}.cachedCount(5)}
}

当我们点击组件时,调用数据源的 pushData 方法,该方法内的实现中包含了 notifyDataAdd 方法,这会通知 LazyForEach 有数据增加,LazyForEach 随即新建子组件。

适合场景

按需加载数据的场景,优化容器组件内存使用量的场景。

LazyForEach:数据懒加载https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-rendering-control-lazyforeach-V5

多线程

使用多线程来优化密集计算和高延迟任务。

可参考我的上一篇文章:【鸿蒙应用开发】多线程并发(Stage模型)

taskpool 

使用任务池来提交任务,在其内部维护了统一的线程管理(负载均衡,动态调度等),任务多会自动扩容,长时间没任务会缩容,减少占用。

taskpool 提供了众多 API 帮助你构建更为强大的 任务调度,支持:

  • 设置任务优先级
  • 设置延迟执行时间
  • 设置周期性执行任务
  • 取消任务池任务
  • 任务组
  • 长时任务
  • 串行队列

其实还有很多不一一列举,总之就是非常强大。

戳下面的链接看全部的API:

taskpool 的API参考https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-taskpool-V5#state10

worker 

worker 也是一种并发多线程机制,你可以通过分离宿主线程和工作线程来加快处理效率,相比 taskpool,worker 个人认为更加的轻量,它使用简单,非常适合长运行时间,如:文件下载,文件读写等耗时任务。

虽说其 API 设计简单,但在实际使用上也暴露出功能匮乏,在一些需要进行任务取消,调度逻辑复杂的场景,它表现不太良好,不过我们本篇文章仅讨论它作为性能优化的一个方向。

Worker简介https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/worker-introduction-V5

适用场景

在多线程方面我们讨论了两种并发机制,它们各有千秋,在适用场景上当然有所不同。

如果你希望进行文件下载,文件读写等耗时任务,那么 worker 在其使用简单、高效API方面更具优势。

如果你希望定制任务调度逻辑,存在任务取消,任务调度复杂等情况时(比如你正在展示图片瀑布流,图片并行加载,若滑动超出范围则取消加载),taskpool 可能更适合。

官方对 worker 和 taskpool 也进行了比较,并对他们的适用场景做了详细对比,(总的来说官方更希望你尽可能用 taskpool, 它占用更小,API 更加强大,适用面更广。)

TaskPool和Worker的对比 (TaskPool和Worker)https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/taskpool-vs-worker-V5

状态管理

不使用状态变量强行更新非状态变量关联组件

以下是它的例子:

@Entry
@Component
struct MyComponent {@State needsUpdate: boolean = true;realStateArr: Array<number> = [4, 1, 3, 2]; // 未使用状态变量装饰器realState: Color = Color.Yellow;updateUIArr(param: Array<number>): Array<number> {const triggerAGet = this.needsUpdate;return param;}updateUI(param: Color): Color {const triggerAGet = this.needsUpdate;return param;}build() {Column({ space: 20 }) {ForEach(this.updateUIArr(this.realStateArr),(item: Array<number>) => {Text(`${item}`)})Text("add item").onClick(() => {// 改变realStateArr不会触发UI视图更新this.realStateArr.push(this.realStateArr[this.realStateArr.length-1] + 1);// 触发UI视图更新this.needsUpdate = !this.needsUpdate;})Text("chg color").onClick(() => {// 改变realState不会触发UI视图更新this.realState = this.realState == Color.Yellow ? Color.Red : Color.Yellow;// 触发UI视图更新this.needsUpdate = !this.needsUpdate;})}.backgroundColor(this.updateUI(this.realState)).width(200).height(500)}
}

以上是官方的代码示例,总的来说,你别用一个受状态管理的变量去强行改变非状态管理的变量的组件。很拗口对么? 看懂上面的代码你就能明白我在说什么哈哈。

官方的更多优化建议(状态管理相关)

上面这个例子其实也是我从官方找到的,官方梳理了很多状态管理中的优秀实践,戳:

状态管理优秀实践https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-state-management-best-practices-V5面试的时候,如果你把状态管理方面的性能优化按照上面的优秀实践说,那简直是核弹级别的回答。

未完待续

疯狂码字中。。。。

 如果觉得有用,点个赞支持一下呗(能关注一下就更好啦)。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词