👋 你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】
   我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 HarmonyOS 的过程都记录在这里。
  
  🛠️ 主要方向:ArkTS 语言基础、HarmonyOS 原生应用(Stage 模型、UIAbility/ServiceAbility)、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战,以及 Android → 鸿蒙的迁移踩坑与复盘。
  🧭 内容节奏:从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘,让每篇都有可落地的代码与方法论。
  💡 我相信:写作是把知识内化的过程,分享是让生态更繁荣的方式。
  
   如果你也想拥抱鸿蒙、热爱成长,欢迎关注我,一起交流进步!🚀

前言

页面开发完成以后,经常会听到一句评价:“我手机上点起来挺流畅的。”

这句话可以说明页面至少能正常使用,却不能直接当成性能结论。同一个页面,在不同设备、不同操作路径、不同数据量下,点击响应、页面完成显示和转场过程可能是三件不同的事。真正要判断一个页面是不是“卡”,更合适的方式是把主观感受拆成可以测量的指标。

华为官方提供的 DevEco Testing 就适合做这件事。其性能基础质量测试可以模拟用户操作,对应用启动、应用内滑动、点击以及资源占用等场景进行性能评估,涉及点击时延、帧率、内存、CPU 负载等指标,并提供过程截图及底层性能采集日志。

这次不做复杂业务,把场景缩小到一个最容易复现的问题:从列表页点击进入详情页,检查页面转场的响应时延、完成时延和卡顿表现,再根据报告决定下一步应该查哪里。

一、“我手机上很流畅”为什么不是性能结论

人的主观感受很容易受测试方式影响。

例如点击一个商品卡片进入详情页:

  • 按钮很快出现按压反馈,不代表新页面已经完成显示;
  • 新页面很快出现第一帧,不代表后续转场过程没有掉帧;
  • 一台高性能设备表现正常,也不能说明其他目标设备上不存在问题;
  • 只测试一次顺畅路径,也不能代表核心页面的整体性能。

官方的性能体验规则本身也是按具体指标区分的。

当前华为官方“时延”规则中,应用或元服务内点击操作响应时延应 ≤100ms;对于应用,应用内点击操作完成时延应 ≤900ms。这两个指标本来就不是一回事。

可以先这样理解:

指标主要回答的问题
点击响应时延用户点下去以后,界面多久开始作出可见响应
点击完成时延从操作开始,到目标页面完成关键显示需要多久
转场卡顿率页面切换动画过程中是否存在明显掉帧、停顿
滑动响应时延手指开始滑动以后,页面多久开始跟随
滑动卡顿率页面滚动过程中是否持续出现掉帧

因此,当一个页面被评价为“有点慢”时,第一步最好不要直接猜是网络、布局还是 ArkTS 代码,而是先确认到底慢在“响应”“完成”还是“动画过程”。

二、先把 DevEco Testing 能测什么弄清楚

DevEco Testing 当前提供性能基础质量测试和场景化性能测试。

性能基础质量测试偏向直接对应用进行标准化性能检查;场景化性能测试则允许通过脚本定义业务操作流,对实际使用场景进行性能评估,并提供步骤级操作视频以及 Perfdata 性能日志。

对于本文这种“进入页面到底慢不慢”的问题,先从基础质量测试入手就够了。

测试对象可以归纳成三类:

页面点击。
例如首页点击卡片进入详情页,重点看点击响应时延和点击完成时延。

页面转场。
例如 Navigation 页面切换,除了时延,还要看切换动画期间的卡顿表现。

页面滑动。
例如 List、Grid、WaterFlow 等内容区域滚动,可以继续看滑动响应和卡顿。

如果后续需要更精确地固定业务流程,再考虑场景化性能测试,不必一开始就把测试脚本做得很复杂。

三、准备一个最小测试应用

为了避免网络、数据库、图片下载等因素干扰,本例只准备两个页面:

Home
 └── 点击“打开详情页”
       ↓
Detail
 ├── 标题
 ├── 若干文本内容
 └── 可滚动列表

测试目标也保持简单:

  1. 测试 Home → Detail 的页面转场;
  2. 观察点击响应时延;
  3. 观察点击完成时延;
  4. 观察转场卡顿;
  5. 在 Detail 中滑动列表,再观察滑动性能。

页面路由采用官方目前推荐的 Navigation + NavPathStack 方式。

官方文档说明,从 API version 10 开始,更推荐使用 NavPathStack 实现 Navigation 页面路由;NavPathStack 用于管理 Navigation 的路由栈,可以完成页面跳转、返回、替换、删除等操作。

这里不需要为了性能测试专门接入某个应用侧“性能 SDK”。测试对象就是正常运行的 HarmonyOS 页面。

四、用 Navigation 搭一个可测试页面

这段代码只解决一个问题:构造一个清晰、稳定、容易重复操作的页面跳转场景。

@Entry
@Component
struct Index {
  private pageStack: NavPathStack = new NavPathStack();

  @Builder
  pageMap(name: string) {
    if (name === 'DetailPage') {
      DetailPage();
    }
  }

  build() {
    Navigation(this.pageStack) {
      Column({ space: 24 }) {
        Text('Performance Test Home')
          .fontSize(28)
          .fontWeight(FontWeight.Bold)

        Text('点击按钮进入详情页,用于观察页面转场性能。')
          .fontSize(16)

        Button('打开详情页')
          .onClick(() => {
            this.pageStack.pushPathByName('DetailPage', undefined);
          })
      }
      .width('100%')
      .height('100%')
      .padding(24)
      .justifyContent(FlexAlign.Center)
    }
    .title('Home')
    .mode(NavigationMode.Stack)
    .navDestination(this.pageMap)
  }
}

@Component
struct DetailPage {
  build() {
    NavDestination() {
      Column({ space: 16 }) {
        Text('Detail Page')
          .fontSize(28)
          .fontWeight(FontWeight.Bold)

        Text('下面放一些可滚动内容,用于继续观察页面滑动表现。')
          .fontSize(16)

        List({ space: 12 }) {
          ForEach(
            Array.from({ length: 40 }, (_, index) => index),
            (item: number) => {
              ListItem() {
                Text(`Item ${item + 1}`)
                  .fontSize(18)
                  .width('100%')
                  .padding(16)
                  .backgroundColor('#F2F3F5')
                  .borderRadius(12)
              }
            }
          )
        }
        .layoutWeight(1)
        .width('100%')
      }
      .width('100%')
      .height('100%')
      .padding(24)
    }
    .title('Detail')
  }
}

这里真正需要关注的不是页面样式,而是三件事。

第一,Navigation 持有一个明确的 NavPathStack。

第二,通过 pushPathByName() 触发从 Home 到 NavDestination 的页面切换。官方 Navigation 路由文档明确给出了基于 NavPathStack 进行页面管理和跳转的方式。

第三,详情页中保留一个 List,这样一次测试既能覆盖页面转场,也能继续观察滑动表现。

这个示例没有加入网络请求、图片解码或者数据库读取,是有意为之。性能排查最好先建立一个可重复的基线,再逐步增加真实业务因素。

五、配置性能测试时,页面遍历到底在做什么

准备好待测应用以后,可以在 DevEco Testing 中创建性能测试任务,并选择已经安装到测试设备上的应用。

官方对性能基础质量测试的定义就是“模拟用户操作”,覆盖启动、应用内滑动、点击等场景。

因此,页面遍历不是漫无目的地把整个应用点一遍。

对于本文的测试场景,更合理的遍历路线是:

启动应用
  ↓
Home
  ↓ 点击“打开详情页”
Detail
  ↓
向上滑动列表
  ↓
返回 Home

如果应用里还有搜索页、订单页、设置页,可以分别建立测试路径。不要为了“覆盖率”在一次性能任务里塞进大量互不相关的操作,否则最终看到某个异常指标时,很难快速对应到具体业务动作。

性能测试真正需要的是稳定、明确、可以重复的业务路径。

六、响应时延:用户点完以后,页面什么时候开始回应

这是最容易被“感觉挺快”掩盖的指标。

官方当前性能体验规则给出的点击操作响应要求为:

应用或元服务内点击操作响应时延应 ≤100ms。

这里不要把响应时延理解成“详情页完全加载完”。

它关注的是操作发生以后,界面多久开始产生响应。

例如点击“打开详情页”以后:

用户点击
   │
   ├── 页面开始发生可见变化  ← 响应
   │
   ├── 页面继续构建 / 渲染
   │
   └── 目标页面完成显示       ← 完成

这两个时间点不同,因此才需要同时观察响应时延和完成时延。

如果响应时延异常,排查重点应该靠近操作发生后的前半段,而不是看到“页面慢”就直接去优化整个详情页。

七、完成时延:页面动了,不代表页面已经准备好

官方当前规则中,应用内点击操作完成时延应 ≤900ms。

这个指标比响应时延更容易受到业务页面复杂度影响。

假设 Detail 页面后来加入这些逻辑:

点击商品
 ↓
创建目标页面
 ↓
读取本地缓存
 ↓
构建复杂组件树
 ↓
处理图片
 ↓
更新状态
 ↓
页面完成显示

用户点击以后可能马上看到转场,所以主观上觉得“已经响应了”;但如果目标页面迟迟没有进入稳定可用状态,完成时延仍然可能出现问题。

因此:

响应快 + 完成慢

和

响应本身就慢

是两种不同的问题。

这也是性能数据比“感觉卡”更有价值的地方。

八、完成时延正常,也要继续看卡顿

还有一种常见情况:

页面进入速度并不慢,但动画过程中有明显顿挫。

这时只看完成时延就不够了。

官方 AppAnalyzer 对 DevEco Testing 报告的诊断能力明确包含页面间转场的:

  • 点击响应时延;
  • 点击完成时延;
  • 转场卡顿率。

对于页面滑动,还可以分析滑动响应时延和滑动卡顿率。

因此性能判断最好至少形成下面这个组合:

响应时延
+
完成时延
+
转场/滑动卡顿

而不是只拿一个数字判断页面好坏。

华为官方 SmartPerf 场景化采集资料也将页面切换的 ResponseTime、CompleteTime、HitchTimeRate 分开记录,并说明页面切换卡顿率与切换动效期间累计丢帧时间有关。

九、怎么阅读测试报告

跑完测试以后,不建议先盯着“通过/不通过”几个字。

更有效的阅读方式是从操作场景往回找。

例如发现:

Home → Detail
点击完成时延异常

先确认异常发生在哪一次操作,再观察当时的截图、日志和性能数据。

如果后续需要进一步定位,DevEco Testing 的性能报告还可以导入 DevEco Studio 的 AppAnalyzer。

官方文档说明,从 DevEco Studio 6.0.0 Beta3 开始,支持将 DevEco Testing 产生的性能检测报告导入 AppAnalyzer;AppAnalyzer 可以针对其中支持的指标继续诊断,并提供调优文件、时间戳、分析文档以及优化建议。

当前流程可以理解成:

DevEco Testing
     │
     │ 发现“哪一个业务场景表现异常”
     ▼
性能测试报告
     │
     │ 导出报告
     ▼
AppAnalyzer
     │
     │ 继续进行问题诊断
     ▼
Profiler / trace / 调用栈
     │
     ▼
定位具体耗时位置

这里比较容易出现一个理解偏差:

DevEco Testing 和 AppAnalyzer 不是同一个测试入口。

官方也明确提示,两者在检测能力、检测方法以及场景识别方面存在差异,因此直接使用 AppAnalyzer 检测,与导入 DevEco Testing 报告进行诊断,结果可能不完全一致。

不要拿两套不同测试流程的结果做机械的一一对比。

十、根据数据决定下一步优化什么

拿到数据以后,比“马上改代码”更重要的是先判断问题属于哪一类。

响应时延高

重点检查点击操作之后、界面开始反馈之前发生了什么。

例如是否把过多同步工作放在用户操作后的关键路径上。

先定位,再调整,不要凭报告里的一个数字直接删除业务逻辑。

响应正常,完成时延高

说明用户操作以后已经较快得到反馈,但目标内容达到完成状态所需时间仍然偏长。

这时更应该关注:

  • 目标页面构建过程;
  • 页面初始化阶段执行的任务;
  • 数据处理;
  • 组件树复杂度;
  • 资源准备过程。

具体是哪一个环节,需要结合 Profiler 或 trace 再确认。

时延正常,但转场卡顿

这时问题重点就从“多久完成”转向“完成过程是不是平滑”。

应该继续查看转场期间的渲染和帧表现。

页面切换正常,但列表滑动卡顿

不要继续围着 Navigation 查。

测试场景已经变化到页面滑动,应单独观察滑动响应、滑动卡顿,并检查对应滚动区域的构建和更新行为。

这也是做性能测试时很重要的一条原则:指标对应场景,场景对应代码路径。

十一、几个容易理解错的地方

1. 不要把响应时延和完成时延当成同一个指标

两者对应的是不同阶段。

只看其中一个,都可能漏掉真正的问题。

2. 不要自己编一个“流畅阈值”

对于本文涉及的点击操作,直接使用官方性能体验规则提供的标准更可靠。

当前官方给出的应用内点击操作规则是:

响应时延 ≤ 100ms
应用点击完成时延 ≤ 900ms

规则变化时,应以当前官方文档为准。

3. 测试路径不要太复杂

一次把登录、搜索、详情、支付、设置全部串起来,报告确实会更多,但异常与具体业务动作之间的关系反而更难确认。

核心页面拆开测通常更容易定位。

4. 不要因为“自己设备没卡”就跳过测试

性能标准针对的是具体指标,而不是开发者主观判断。

开发机上的一次顺畅操作只能算观察结果,不是性能数据。

5. DevEco Testing 找问题,Profiler 更适合继续找原因

DevEco Testing 可以帮助确认哪个业务场景、哪个性能指标出现异常;当问题需要深入到调用栈、trace 或具体时间段时,再进入 AppAnalyzer、Profiler 继续分析。

工具之间最好形成递进关系,而不是互相替代。

十二、实际项目可以按这个顺序排查

面对“这个页面感觉有点卡”,可以按下面的顺序处理:

1. 固定测试设备和应用版本
            ↓
2. 固定业务操作路径
            ↓
3. 用 DevEco Testing 执行性能测试
            ↓
4. 区分响应时延 / 完成时延 / 卡顿
            ↓
5. 找到发生问题的具体页面操作
            ↓
6. 导出性能报告
            ↓
7. 必要时导入 AppAnalyzer
            ↓
8. 使用 Profiler / trace 深入定位
            ↓
9. 修改代码
            ↓
10. 使用相同路径重新测试

最重要的是最后一步。

如果优化前后测试条件、页面路径和数据状态完全不同,那么两个数字本身就很难比较。

所以性能优化不是“看一次报告然后改代码”,而应该形成:

发现问题 → 定位问题 → 修改 → 同场景复测

这样一个闭环。

开发经验总结

DevEco Testing 的价值,并不是给页面简单贴一个“流畅”或者“不流畅”的标签,而是帮助我们把“感觉有点卡”拆成能够继续分析的问题。

这次最值得保留的几个思路是:

  • 页面性能不要只凭开发者自己的设备体验判断;
  • 点击响应时延和点击完成时延是两个不同阶段的指标;
  • 页面完成速度正常,并不意味着转场过程不存在卡顿;
  • 一次性能测试最好对应一条清楚、可重复的业务路径;
  • DevEco Testing 更适合先发现场景问题,必要时再结合 AppAnalyzer、Profiler 和 trace 继续定位;
  • 优化完成后,应使用相同业务路径重新测试,而不是换一个场景验证。

如果一个页面现在只是“感觉不太顺”,不妨先别急着重构。把一次点击拆成响应、完成和转场三个阶段,通常比直接猜是哪段代码慢,更容易找到真正值得优化的位置。

📝 写在最后

如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!

我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!

感谢你的阅读,我们下篇文章再见~👋

✍️ 作者:菜鸟不学编程
🧵 本文原创,转载请注明出处。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐