第2篇|鸿蒙页面越写越卡?先别急着优化算法,我最后查到是生命周期和动画叠加

摘要:页面卡顿不一定是“大问题”。这次我碰到的情况是 CPU 不高、功能也正常,但页面越用越钝。最后真正拖慢体验的,不是算法,而是重复刷新、搜索高频触发和热路径上的重动画叠加到了一起。

很多人排查性能问题时,第一反应都是“是不是计算太重了”。但我这次在鸿蒙项目里遇到的卡顿,并不是那种一眼就能看出来的高负载问题,而是一种更常见、也更容易被忽略的体感变慢。

应用能跑,页面也没崩,CPU 看着也不高,可就是切页发涩、列表刷新发黏、搜索输入不跟手。你说它坏了,它又没完全坏;你说它没问题,用户一上手马上就能感觉出来。

问题现象

  • 列表页切换和详情页返回明显变慢。
  • 搜索框输入后,结果刷新不跟手,甚至会连续触发多次刷新。
  • 编辑页偶尔没有明显掉帧,但整体操作“发闷”。
  • 任务管理器看起来 CPU 不高,说明问题不一定是纯算力瓶颈。

根因分析

这次我最后定位到的,不是一个点,而是三个小问题叠加:

  1. aboutToAppear 和第一次 onPageShow 对同一份数据做了重复刷新。
  2. 搜索输入没有防抖,用户每输入一个字都触发一次完整刷新。
  3. tab 切换和编辑态切换用了偏重的动画,恰好又落在高频交互路径上。

单看每一项都不算致命,但它们叠起来以后,页面就会越来越“肉”。

我是怎么修的

1. 先确认是不是“重复刷新”,而不是直接开大招优化

我建议性能排查第一步先看生命周期,不要一上来就怀疑数据层。因为很多体感卡顿并不是算得慢,而是算了两次、刷了两次、动画播了两次。

我这次最先收敛的点,就是首次进入页面时,aboutToAppear 已经做了数据准备,而第一次 onPageShow 又把同样的刷新再做了一遍。

2. 给首次 onPageShow 加保护,避免首进页面重复刷新

示意代码:

private hasEnteredOnce: boolean = false

onPageShow() {
  if (!this.hasEnteredOnce) {
    this.hasEnteredOnce = true
    return
  }
  this.refreshList()
}

如果首屏数据已经在 aboutToAppear 里准备完了,那么第一次 onPageShow 通常不应该再重复刷一次。

3. 搜索输入做轻量防抖,比“每次都刷”更实用

搜索框最容易在不经意间变成高频刷新入口。我最后没有上复杂方案,只做了一个很轻的防抖,收益就很明显。

private searchTimer?: number

onSearchChange(value: string) {
  this.keyword = value
  clearTimeout(this.searchTimer)
  this.searchTimer = setTimeout(() => {
    this.refreshList()
  }, 220)
}

这个改动看起来很小,但对输入跟手感帮助很大。

4. 热路径上的动画要克制

很多动画在静态展示页、欢迎页、空状态页上是加分项,但如果你把大动画放进列表切换、编辑态切换、筛选器响应这些高频入口里,它们就会从“提升质感”变成“拖慢交互”。

我这次做了两个很直接的处理:

  • 缩短 tab 切换动画时长
  • 避免在高频动作里同时改宽高、字号、透明度这类成本更高的属性

例如:

animateTo({ duration: 160, curve: Curve.EaseOut }, () => {
  this.activeTab = nextTab
})

5. ForEach 的 key 要稳定

这个点经常被忽略。列表项 key 如果不稳,框架可能会把“局部更新”误判成“整块重建”。你看到的只是改了一条数据,实际渲染层可能已经做了更多无谓工作。

修完以后怎么验证

我当时验证的重点不是“帧率有没有提升几个百分点”,而是下面这些更贴近真实体验的现象:

  • 首次进入页面时,列表是不是只刷新了一次。
  • 搜索输入时,结果刷新是否更跟手。
  • 切换 tab 和进入编辑态时,动画有没有从“拖”变成“利落”。
  • 整体体感是否改善,而不是只看某一项监控指标。

这次踩坑我得出的结论

  • 页面卡顿先查生命周期刷新重叠,命中率往往比先查算法更高。
  • 搜索和筛选是最常见的隐形高频入口,防抖往往比复杂优化更值。
  • 动画不是越多越好,放在热路径里尤其要克制。
  • CPU 不高不代表没问题,很多体验型卡顿本质上是“做了太多次没必要的事”。

可以直接带走的排查顺序

如果你的鸿蒙页面“没崩但很卡”,我建议按这个顺序查:

  1. aboutToAppearonPageShow 是否重复刷新同一份数据。
  2. 搜索框、筛选器、分页切换是否缺少防抖或节流。
  3. 高频交互里有没有放过重的动画。
  4. 列表 key 是否稳定,是否导致额外重建。

很多“玄学卡顿”,最后并不是某个大 bug,而是几个小地方同时没有收住。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐