注:本文转载自 HarmonyOS 官网文档

开发者若使用低性能的代码实现功能场景可能不会影响应用的正常运行,但却会对应用的性能造成负面影响。本章节列举出了一些可提升性能的场景供开发者参考,以避免应用实现上带来的性能劣化。

使用数据懒加载

开发者在使用长列表时,如果直接采用循环渲染方式,如下所示,会一次性加载所有的列表元素,一方面会导致页面启动时间过长,影响用户体验,另一方面也会增加服务器的压力和流量,加重系统负

 
@Entry
@Component
struct MyComponent {
@State arr: number[] = Array.from(Array(100), (v,k) =>k); //构造0-99的数组
build() {
List() {
ForEach(this.arr, (item: number) => {
ListItem() {
Text(`item value: ${item}`)
}
}, (item: number) => item.toString()) public getData(index: number): any { return this.dataArray[index] }

上述代码会在页面加载时将 100 个列表元素全部加载,这并非我们需要的,我们希望从数据源中按需迭代加载数据并创建相应组件,因此需要使用数据懒加载,如下所示:

class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [] public totalCount(): number {
return 0
} public getData(index: number): any {
return undefined
} registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener')
this.listeners.push(listener)
}
} unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener')
this.listeners.splice(pos, 1)
}
} notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
} notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
} notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
} notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
} notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
} class MyDataSource extends BasicDataSource {
private dataArray: string[] = ['item value: 0', 'item value: 1', 'item value: 2'] public totalCount(): number {
return this.dataArray.length
} public getData(index: number): any {
return this.dataArray[index]
} public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(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() build() {
List() {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
Text(item).fontSize(20).margin({ left: 10 })
}
}
.onClick(() => {
this.data.pushData('item value: ' + this.data.totalCount())
})
}, item => item)
}
}
}

  

上述代码在页面加载时仅初始化加载三个列表元素,之后每点击一次列表元素,将增加一个列表元素。

设置 List 组件的宽高

在使用 Scroll 容器组件嵌套 List 组件加载长列表时,若不指定 List 的宽高尺寸,则默认全部加载。

说明

Scroll 嵌套 List 时:

● List 没有设置宽高,会布局 List 的所有子组件。

● List 设置宽高,会布局 List 显示区域内的子组件。

● List 使用ForEach加载子组件时,无论是否设置 List 的宽高,都会加载所有子组件。

● List 使用LazyForEach加载子组件时,没有设置 List 的宽高,会加载所有子组件,设置了 List 的宽高,会加载 List 显示区域内的子组件。

class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [] public totalCount(): number {
return 0
} public getData(index: number): any {
return undefined
} registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener')
this.listeners.push(listener)
}
} unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
      console.info('remove listener')
this.listeners.splice(pos, 1)
}
} notifyDataReload(): void {
this.listeners.forEach(listener => {
      listener.onDataReloaded()
})
} notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataAdd(index)
})
} notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataChange(index)
})
} notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataDelete(index)
})
} notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
      listener.onDataMove(from, to)
})
}
} class MyDataSource extends BasicDataSource {
private dataArray: Array<string> = new Array(100).fill('test') public totalCount(): number {
return this.dataArray.length
} public getData(index: number): any {
return this.dataArray[index]
} public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(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() build() {
Scroll() {
List() {
LazyForEach(this.data, (item: string, index: number) => {
ListItem() {
Row() {
Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
}
}
})
}
}
}
}

  

因此,此场景下建议设置 List 子组件的宽高。

class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [] public totalCount(): number {
return 0
} public getData(index: number): any {
return undefined
} registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener')
this.listeners.push(listener)
}
} unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
      console.info('remove listener')
this.listeners.splice(pos, 1)
}
} notifyDataReload(): void {
this.listeners.forEach(listener => {
      listener.onDataReloaded()
})
} notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataAdd(index)
})
} notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataChange(index)
})
} notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
      listener.onDataDelete(index)
})
} notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
      listener.onDataMove(from, to)
})
}
} class MyDataSource extends BasicDataSource {
private dataArray: Array<string> = new Array(100).fill('test') public totalCount(): number {
return this.dataArray.length
} public getData(index: number): any {
return this.dataArray[index]
} public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(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() build() {
Scroll() {
List() {
LazyForEach(this.data, (item: string, index: number) => {
ListItem() {
Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
}.width('100%')
})
}.width('100%').height(500)
}.backgroundColor(Color.Pink)
}
}

  

使用条件渲染替代显隐控制

如下所示,开发者在使用 visibility 通用属性控制组件的显隐状态时,仍存在组件的重新创建过程,造成性能上的损耗。

@Entry
@Component
struct MyComponent {
  @State isVisible: Visibility = Visibility.Visible;   build() {
    Column() {
      Button("显隐切换")
        .onClick(() => {
          if (this.isVisible == Visibility.Visible) {
            this.isVisible = Visibility.None
          } else {
            this.isVisible = Visibility.Visible
          }
        })
      Row().visibility(this.isVisible)
        .width(300).height(300).backgroundColor(Color.Pink)
    }.width('100%')
  }
}

  

要避免这一问题,可使用 if 条件渲染代替 visibility 属性变换,如下所示:

@Entry
@Component
struct MyComponent {
  @State isVisible: boolean = true;   build() {
    Column() {
      Button("显隐切换")
        .onClick(() => {
          this.isVisible = !this.isVisible
        })
      if (this.isVisible) {
        Row()
          .width(300).height(300).backgroundColor(Color.Pink)
      }
    }.width('100%')
  }
}

  

使用 Column/Row 替代 Flex

由于 Flex 容器组件默认情况下存在 shrink 导致二次布局,这会在一定程度上造成页面渲染上的性能劣化。

@Entry
@Component
struct MyComponent {
  build() {
    Flex({ direction: FlexDirection.Column }) {
      Flex().width(300).height(200).backgroundColor(Color.Pink)
      Flex().width(300).height(200).backgroundColor(Color.Yellow)
      Flex().width(300).height(200).backgroundColor(Color.Grey)
    }
  }
}

  

上述代码可将 Flex 替换为 Column、Row,在保证实现的页面布局效果相同的前提下避免 Flex 二次布局带来的负面影响。

@Entry
@Component
struct MyComponent {
  build() {
    Column() {
      Row().width(300).height(200).backgroundColor(Color.Pink)
      Row().width(300).height(200).backgroundColor(Color.Yellow)
      Row().width(300).height(200).backgroundColor(Color.Grey)
    }
  }
}

减少应用滑动白块

应用通过增大 List/Grid 控件的 cachedCount 参数,调整 UI 的加载范围。cachedCount 表示屏幕外 List/Grid 预加载 item 的个数。

如果需要请求网络图片,可以在 item 滑动到屏幕显示之前,提前下载好内容,从而减少滑动白块。

如下是使用 cachedCount 参数的例子:

@Entry
@Component
struct MyComponent {
  private source: MyDataSource = new MyDataSource();   build() {
    List() {
      LazyForEach(this.source, item => {
        ListItem() {
          Text("Hello" + item)
            .fontSize(50)
            .onAppear(() => {
              console.log("appear:" + item)
            })
        }
      })
    }.cachedCount(3) // 扩大数值appear日志范围会变大
  }
} class MyDataSource implements IDataSource {
  data: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];   public totalCount(): number {
    return this.data.length
  }   public getData(index: number): any {
    return this.data[index]
  }   registerDataChangeListener(listener: DataChangeListener): void {
  }   unregisterDataChangeListener(listener: DataChangeListener): void {
  }
}

  

使用说明:

cachedCount 的增加会增大 UI 的 cpu、内存开销。使用时需要根据实际情况,综合性能和用户体验进行调整。

点击关注阅读原文,了解更多精彩资讯

HarmonyOS—UI 开发性能提升的推荐方法的更多相关文章

  1. 提高 Web开发性能的 10 个方法

    随着网络的高速发展,网络性能的持续提高成为能否在芸芸App中脱颖而出的关键.高度联结的世界意味着用户对网络体验提出了更严苛的要求.假如你的网站不能做到快速响应,又或你的App存在延迟,用户很快就会移情 ...

  2. Android性能优化之UI渲染性能优化

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本篇博客主要记录一些工作中常用的UI渲染性能优化及调试方法,理解这些方法对于我们编写高质量代码也是有一些帮助的,主要内容包括介绍CPU,GPU的职 ...

  3. Atitit 项目管理 提升开发效率的项目流程方法模型 哑铃型  橄榄型 直板型

    Atitit 项目管理 提升开发效率的项目流程方法模型 哑铃型  橄榄型 直板型 项目主体三个部分 ui界面,中间层,数据库 按照不同的比重可以分为一下三个模型  哑铃型  橄榄型 直板型 哑铃型 开 ...

  4. 用直接路径(direct-path)insert提升性能的两种方法

    1.传统串行insert方式 常见的insert方式有两种: (1) insert into table_name values(....) (2) insert into target_table ...

  5. 提升PHP性能的21种方法

    提升PHP性能的21种方法. 1.用单引号来包含字符串要比双引号来包含字符串更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会.2.如果能将类的方法定义成static,就尽量定义成st ...

  6. 初探性能优化——2个月到4小时的性能提升(copy)推荐阅读

    一直不知道性能优化都要做些什么,从哪方面思考,直到最近接手了一个公司的小项目,可谓麻雀虽小五脏俱全.让我这个编程小白学到了很多性能优化的知识,或者说一些思考方式.真的感受到任何一点效率的损失放大一定倍 ...

  7. 精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能)

    原文:精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能) 本篇博客主要说明如何使用 UI Virtualization(以下简称为 UIV) 来提 ...

  8. ASP.NET网站性能提升的几个方法

    1. HTTP 压缩 HTTP 压缩通常用于压缩从服务端返回的页面内容.它压缩HTTP请求和响应,这个会是巨大的性能提升.我的项目是基于Window Server 2003开发的,可以参考这篇文章. ...

  9. APP开发中,如何从UI设计上提升APP用户体验

    设计中有很多细微的东西要注意,就如UI设计中,元素的统一性,图标风格.段落的排版等等,只有能注意这些细节,你的 APP UI 才算合格. 干货君总结了17个提升用户体验的 UI 设计小技巧,也是我们日 ...

  10. 提升 Web开发性能的 10 个技巧

    随着网络的高速发展,网络性能的持续提高成为能否在芸芸App中脱颖而出的关键.高度联结的世界意味着用户对网络体验提出了更严苛的要求.假如你的网站不能做到快速响应,又或你的App存在延迟,用户很快就会移情 ...

随机推荐

  1. 【Azure Developer】使用 Azure VM 上的用户分配托管标识访问 Azure Key Vault 中国区代码示例

    问题描述 在Global版本的Azure Key Vault 文档中,有一节介绍在Azure VM中使用标识获取访问令牌,调用Key Vault中的资源.但是在示例中,只有curl的命令执行,而没有代 ...

  2. 【Azure 事件中心】China Azure上是否有Kafka服务简答

    问题描述 China Azure 上是否有Kakfa服务可以使用呢? 问题回答 China Azure并没有专门的Kafka服务,但是可以使用Azure Event Hub. 创建标准版及以上的Eve ...

  3. netcat 命令介绍及使用示例

    netcat 命令介绍及使用示例 nc(netcat)是一个强大的网络工具,它可以用于读取和写入数据流,支持 TCP 和 UDP 协议.它常被用于网络调试和网络服务的创建. 一.安装方法 centos ...

  4. Android学习之SQLite数据库存储

    •引言 概念 SQLite数据库,和其他的SQL数据库不同, 我们并不需要在手机上另外安装一个数据库软件,Android系统已经集成了这个数据库: 特点 SQLite是一个轻量级的关系型数据库,运算速 ...

  5. 在更新数据的时候,显示一个软件源里面没有Release文件

  6. Docker 部署GitLabs 版本升级 13.9.x -> 15.3.x

    Gitlabs版本升级大版本不能直接跳级升级, 可以参考官方的升级路径.本人是从13.9.x需要升级到最新的15.3.x. 参考官方路径结合自己的实际情况成功升级. 13.9.0 -> 13.1 ...

  7. 基于C#的壁纸管理器(插件版) - 开源研究系列文章

    这几天无聊,想到原来的壁纸管理器应用能够实现成插件的形式,然后思考了一下,打算把原来壁纸管理器的代码用插件形式来进行实现,于是经过几天的努力,终于完成了插件版的壁纸管理器.以前有写过C#的插件的例子( ...

  8. [深度学习] 计算机视觉低代码工具Supervision库使用指北

    Supervision库是一款出色的Python计算机视觉低代码工具,其设计初衷在于为用户提供一个便捷且高效的接口,用以处理数据集以及直观地展示检测结果.Supervision库的官方开源仓库地址为: ...

  9. python高级技术(网络编程一)

    一  socket是什么 链接socket前要熟悉计算机网络基础请看链接:https://www.cnblogs.com/coderxueshan/p/17344739.html Socket是应用层 ...

  10. 记录--UNI-APP安卓本地打包详细教程(保姆级)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一.开发环境 uni-app 官方文档地址 原生开发者支持 1.Android Studio 下载地址:Android Studio官网 ...