OpenHarmony列表场景性能提升方法

2023年 8月 24日 33.8k 0

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

OpenHarmony列表场景性能提升方法

  • 摘要:列表场景在应用程序中很常见,列表性能非常影响用户体验。本文会介绍开发OpenHarmony列表页面时需要考虑的性能提升方法。
  • 关键字:OpenHarmony HarmonyOS 鸿蒙 懒加载 列表滑动性能 LazyForEach cachedCount IDataSource

概述

列表场景在应用程序中很常见,比如新闻列表,通讯软件消息列表,联系人列表,排行榜,各种账单等。列表性能非常影响用户体验,优化列表性能可以提升用户交互体验。在开发OpenHarmony应用时,常用优化列表性能的方法包含:

  • 懒加载懒加载在需要数据时才加载数据。如果一次性加载所有的列表数据,一方面会导致页面启动时间过长,影响用户体验,另一方面也会增加服务器的压力和流量,加重系统负担。数据懒加载可以从数据源中按需迭代加载数据并创建相应组件。
  • 缓存列表项缓存已经渲染过的列表项可以减少重复渲染的开销。另外,通过把屏幕外列表项预先加载缓存起来,这样也可以提升列表响应速度。
  • 优化页面布局优化渲染布局可以减少不必要的渲染绘制操作,提升列表的流畅度。在优化页面布局时,需要减少视图嵌套层次,移除不必要的组件,保持页面精简。
  • 优化图片加载在列表中包含图片时,优化图片加载可以提高列表的加载速度和流畅度。如果是小图片可以同步下载,避免列表快速滑动时产生图片白块。
  • 组件复用有些场景下的自定义组件具有相同的组件布局结构,仅有状态变量等承载数据的差异。把这样的组件缓存起来,需要使用到该组件时直接复用,减少重复创建和渲染的时间,从而提高应用页面的加载速度和响应速度。

本文会以一个范例应用来介绍开发OpenHarmony列表页面时,如何使用上述方法来提升列表性能。

环境准备

本文会基于Sample聊天实例应用进行讲解,该示例应用是一个仿聊天类应用,使用了静态布局搭建了不同的页面。为了优化内存与性能体验,在部分列表场景使用了懒加载。除了懒加载,本文还会尝试其他性能优化方法。

性能实践

懒加载

开发者在使用长列表时,如果直接采用循环渲染方式,会一次性加载所有的列表元素,会导致页面启动时间过长,影响用户体验。建议开发者使用数据懒加载,从数据源中按需迭代加载数据并创建相应组件。

在使用数据懒加载之前,需要实现懒加载数据源接口IDataSource,该接口定义在OpenHarmony SDK的接口声明文件etscomponentlazy_for_each.d.ts里。还需要为数据源注册数据变更监听器DataChangeListener,在数据变更时调用相应的回调函数。Sample聊天实例应用中,并没有使用到数据变更监视器。数据源类BasicDataSource.ets定义如下,该类是一个abstract抽象类,每个列表的数据源具体实现类可以继承实现该抽象类。

export abstract class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = []

  public abstract totalCount()

  public getData(index: number): any {
    return undefined
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) = 0) {
      this.listeners.splice(pos, 1)
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded()
    })
  }
	......
}

以聊天列表为例,数据源具体类ChatListData实现如下,其中ChatModel类对应聊天列表中列表项,包含用户名、最后一条消息内容,时间戳等信息。数据源类ChatListData中,getData()方法为数据源接口IDataSource中定义的,用于给LazyForEach提供数据;addData()和pushData()为数据源类中定义的方法,可用于给数据源增加数据。Sample聊天实例应用中,使用的模拟数据,并没有从网络上获取,这些增加数据的接口实际上未使用,仅用于后续扩展。

class ChatListData extends BasicDataSource {
  private chatList: Array = []

  public totalCount(): number {
    return this.chatList.length
  }

  public getData(index: number): any {
    return this.chatList[index]
  }

  public addData(index: number, data: ChatModel): void {
    this.chatList.splice(index, 0, data)
    this.notifyDataAdd(index)
  }

  public pushData(data: ChatModel): void {
    this.chatList.push(data)
    this.notifyDataAdd(this.chatList.length - 1)
  }
}

最后看下列表页面的代码,详细代码见文件ChatListPage.ets。

可以看出,在List组件容器中,使用LazyForEach循环生成ListItem列表项,按屏幕展示需要逐次加载所需的数据,实现了懒加载。如果使用ForEach循环会一次性加载所有的数据。

build() {
    Column() {
      List() {
		......
        LazyForEach(this.chatListData, (msg: ChatModel) => {
          ListItem() {
            ChatView({ chatItem: msg, wantParams: this.wantParams, wantFileParams: this.wantFileParams })
          }
        }, (msg: ChatModel) => msg.user.userId)
      }
      .backgroundColor(Color.White)
      .listDirection(Axis.Vertical)
		......
    }
  }

缓存列表项

在OpenHarmony SDK文件list.d.ts中,ListAttribute列表属性类中定义了一个cachedCount属性。

该属性cachedCount用于设置长列表延迟懒加载时列表项ListItem的最少缓存数量,表示屏幕外List/Grid预加载项的个数。

应用通过增大List控件的cachedCount参数,调整UI界面的加载范围。如果需要请求网络图片,可以在列表项滑动到屏幕显示之前,提前下载好内容,从而减少滑动白块。

在Sample聊天实例应用中,并未使能该属性,可以尝试使能该属性。缓存列表项数量,建议设置为当前列表页面屏幕可以展示列表项的2倍,具体设置根据列表页面实际情况进行酌情设置。

如下是使用cachedCount参数的例子,我们设置为缓存20条列表项。当设置cachedCount,可以通过在数据源实现类getData()方法中,添加日志打印来验证。当列表界面滑动时,除了获取屏幕上展示的数据,还会额外获取20条列表项数据缓存起来。

build() {
    Column() {
      List() {
		......
        LazyForEach(this.chatListData, (msg: ChatModel) => {
          ListItem() {
            ChatView({ chatItem: msg, wantParams: this.wantParams, wantFileParams: this.wantFileParams })
          }
        }, (msg: ChatModel) => msg.user.userId)
      }
      .backgroundColor(Color.White)
      .listDirection(Axis.Vertical)
		......
	  .cachedCount(20)
    }
  }

优化渲染布局

在OpenHarmony应用开发时,使用ArkUI Inspector分析列表的界面布局。减少嵌套层次,移除不必要的组件来提升页面响应性能。可以参考文章《OpenHarmony使用ArkUI Inspector分析布局》了解更多。

优化图片加载

分析下Image组件的图片加载流程。syncLoad属性默认为false,创建图片时创建一个异步任务,并使用互斥锁。异步加载图片可以避免阻塞主线程,影响UI交互,适合图片加载较长时间时使用。异步任务和使用互斥锁也是有开销的,也可能会影响内存和性能,需要根据实际业务情况进行设置。

在列表场景下,快速滑动时,图片刷新会出现闪烁, 这时可以设置syncLoad属性为true,使图片同步加载,从而避免出现闪烁,可以解决快速滑动时产生的图片白块。

build() {
		......
        Row() {
          Row() {
            Image(this.chatItem.user.userImage)
			      ......
            .syncLoad(true)
          }
			......
      }
	......
  }

组件复用

在OpenHarmony应用开发时,自定义组件被@Reusable装饰器修饰时表示该自定义组件可以复用。在父自定义组件下创建的可复用组件从组件树上移除后,会被加入父自定义组件的可复用节点缓存里。在父自定义组件再次创建可复用组件时,会通过更新可复用组件的方式,从缓存快速创建可复用组件。

使用装饰器@Reusable标记一个组件属于可复用组件后,还需要实现组件复用声明周期回调函数aboutToReuse,其参数为可复用组件的状态变量。调用可复用自定义组件时,父组件会给子组件传递构造数据。示例代码如下所示:

@Reusable
@Component
struct ReusableChatView {
  @State chatItem: ChatModel = undefined

  aboutToReuse(params) {
    this.chatItem = params.chatItem
  }

  build() {
    ChatView({ chatItem: this.chatItem })
  }
}

注意事项

如果需要验证列表滑动时,列表项中组件的挂载卸载,是否在屏幕上展示,可以调用组件的onAppear、onDisAppear事件。

总结

本文基于Sample聊天实例应用中的聊天列表场景,分析了列表滑动性能的优化方法,包含懒加载、缓存列表项、小图片的同步加载,以及页面布局优化等。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论