HarmonyOS APP性能优化之提升应用冷启动速度

应用启动时延是影响用户体验的关键要素。当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用, 这个启动方式就叫做冷启动。

分析应用冷启动耗时

应用冷启动过程大致可分成以下四个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页,如下图:

1、缩短应用进程创建&初始化阶段耗时

该阶段主要是系统完成应用进程的创建以及初始化的过程,包含了启动页图标(startWindowIcon)的解码。

设置合适分辨率的startWindowIcon

如果启动页图标分辨率过大,解码耗时会影响应用的启动速度,建议启动页图标分辨率不超过256像素*256像素,如下所示:

    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon", // 在这里修改启动页图标,建议不要超过256像素x256像素
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ]

下面使用SmartPerf工具,对使用优化前的启动页图标(4096像素*4096像素)及使用优化后的启动页图标(144像素*144像素)的启动性能进行对比分析。分析阶段的起点为启动Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility的开始点),阶段终点为应用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int的开始点)。

对比数据如下:

阶段开始(秒)阶段结束(秒)阶段时长(秒)
使用优化前的启动页图标5419.4845379735420.3277752660.843237293
使用优化后的启动页图标4186.4368352464186.9087773350.471942089

可见阶段时长已缩短,故设置合适分辨率的startWindowIcon对缩短应用进程创建&初始化阶段耗时是有效的。

2、缩短Application&Ability初始化阶段耗时

该阶段主要是资源加载、虚拟机创建、Application&Ability相关对象的创建与初始化、依赖模块的加载等。

减少import的模块

应用代码执行前,应用程序必须找到并加载import的所有模块,应用程序加载的每个额外的第三方框架或者模块都会增加启动时间,耗时长短取决于加载的第三方框架或者模块的数量和大小。推荐开发者尽可能使用系统提供的模块,按需加载,来缩短应用程序的启动耗时。

以下为示例代码:

// 优化减少import的模块
// import ability from '@ohos.ability.ability';
// import dataUriUtils from '@ohos.ability.dataUriUtils';
// import errorCode from '@ohos.ability.errorCode';
// import featureAbility from '@ohos.ability.featureAbility';
// import particleAbility from '@ohos.ability.particleAbility';
// import wantConstant from '@ohos.ability.wantConstant';
// import common from '@ohos.app.ability.common';
// import Configuration from '@ohos.app.ability.Configuration';
// import contextConstant from '@ohos.app.ability.contextConstant';
// import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
// import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
// import GesturePath from '@ohos.accessibility.GesturePath';
// import GesturePoint from '@ohos.accessibility.GesturePoint';
// import distributedAccount from '@ohos.account.distributedAccount';
// import osAccount from '@ohos.account.osAccount';

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
import logger from '../common/Logger';

export default class EntryAbility extends UIAbility {
  // ...
}

下面使用SmartPerf工具,对优化import的模块前(模块数量20个)及优化import的模块后(模块数量5个)的启动性能进行对比分析。分析阶段的起点为启动Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility的开始点),阶段终点为应用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int的开始点)。

对比数据如下:

阶段开始(秒)阶段结束(秒)阶段时长(秒)
优化import的模块前3042.2593912823046.3856146134.126223331
优化import的模块后4186.4368352464186.9087773350.471942089

可见阶段时长已缩短,故减少import的模块对缩短Application&Ability初始化阶段耗时是有效的。

3、缩短AbilityStage生命周期阶段耗时

该阶段主要是AbilityStage的启动生命周期,执行相应的生命周期回调。

避免在AbilityStage生命周期回调接口进行耗时操作

在应用启动流程中,系统会执行AbilityStage的生命周期回调函数。因此,不建议在这些回调函数中执行耗时过长的操作,耗时操作建议通过异步任务延迟处理或者放到其他线程执行。

在这些生命周期回调里,推荐开发者只做必要的操作,详情可以参考:AbilityStage组件容器

以下为示例代码:

const LARGE_NUMBER = 10000000;
const DELAYED_TIME = 1000;

export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    // 耗时操作
    // this.computeTask();
    this.computeTaskAsync(); // 异步任务
  }

  onAcceptWant(want: Want): string {
    // 仅specified模式下触发
    return 'MyAbilityStage';
  }

  computeTask(): void {
    let count = 0;
    while (count < LARGE_NUMBER) {
      count++;
    }
  }

  private computeTaskAsync(): void {
    setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行
      this.computeTask();
    }, DELAYED_TIME);
  }
}

下面使用SmartPerf工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility的开始点),阶段终点为应用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int的开始点)。

对比数据如下:

阶段开始(秒)阶段结束(秒)阶段时长(秒)
优化前同步执行耗时操作2124.9155581942127.0413545752.125796381
优化后异步执行耗时操作4186.4368352464186.9087773350.471942089

可见阶段时长已缩短,故避免在AbilityStage生命周期回调接口进行耗时操作对缩短AbilityStage生命周期阶段耗时是有效的。

4、缩短Ability生命周期阶段耗时

该阶段主要是Ability的启动生命周期,执行相应的生命周期回调。

避免在Ability生命周期回调接口进行耗时操作

在应用启动流程中,系统会执行Ability的生命周期回调函数。因此,不建议在这些回调函数中执行耗时过长的操作,耗时操作建议通过异步任务延迟处理或者放到其他线程执行。

在这些生命周期回调里,推荐开发者只做必要的操作,下面以UIAbility为例进行说明。关于UIAbility组件生命周期的详细说明,参见UIAbility组件生命周期

const LARGE_NUMBER = 10000000;
const DELAYED_TIME = 1000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    logger.info('Ability onCreate');
    // 耗时操作
    // this.computeTask();
    this.computeTaskAsync(); // 异步任务
  }

  onDestroy(): void {
    logger.info('Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    logger.info('Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        logger.error('Failed to load the content. Cause: ' + JSON.stringify(err) ?? '');
        return;
      }
      logger.info('Succeeded in loading the content. Data: ' + JSON.stringify(data) ?? '');
    });

    // 耗时操作
    // this.computeTask();
    this.computeTaskAsync(); // 异步任务
  }

  onWindowStageDestroy(): void {
    logger.info('Ability onWindowStageDestroy');
  }

  onForeground(): void {
    logger.info('Ability onForeground');
    // 耗时操作
    // this.computeTask();
    this.computeTaskAsync(); // 异步任务
  }

  onBackground(): void {
    logger.info('Ability onBackground');
  }

  computeTask(): void {
    let count = 0;
    while (count < LARGE_NUMBER) {
      count++;
    }
  }

  private computeTaskAsync(): void {
    setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行
      this.computeTask();
    }, DELAYED_TIME);
  }
}

下面使用SmartPerf工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility的开始点),阶段终点为应用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int的开始点)。

对比数据如下:

阶段开始(秒)阶段结束(秒)阶段时长(秒)
优化前同步执行耗时操作1954.9876300361957.5659645042.578334468
优化后异步执行耗时操作4186.4368352464186.9087773350.471942089

可见阶段时长已缩短,故避免在Ability生命周期回调接口进行耗时操作对缩短Ability生命周期阶段耗时是有效的。

5、缩短加载绘制首页阶段耗时

该阶段主要是加载首页内容、测量布局、刷新组件并绘制。

自定义组件生命周期回调接口里避免耗时操作

自定义组件的生命周期变更会调用相应的回调函数。

aboutToAppear函数会在创建自定义组件实例后,页面绘制之前执行,以下代码在aboutToAppear中对耗时间的计算任务进行了异步处理,避免在该接口执行该耗时操作,不阻塞页面绘制。

以下为示例代码:

const LARGE_NUMBER = 10000000;
const DELAYED_TIME = 1000;

@Entry
@Component
struct Index {
  @State private text: string = "";
  private count: number = 0;

  aboutToAppear() {
    // 耗时操作
    // this.computeTask();
    this.computeTaskAsync(); // 异步任务
    let context = getContext(this) as Context;
    this.text = context.resourceManager.getStringSync($r('app.string.startup_text'));
  }

  build() {
    Column({ space: 10 }) {
      Text(this.text).fontSize(50)
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }

  computeTask(): void {
    this.count = 0;
    while (this.count < LARGE_NUMBER) {
      this.count++;
    }
    let context = getContext(this) as Context;
    this.text = context.resourceManager.getStringSync($r('app.string.task_text'));
  }

  // 运算任务异步处理
  private computeTaskAsync(): void {
    setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行
      this.computeTask();
    }, DELAYED_TIME);
  }
}

下面使用SmartPerf工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility的开始点),阶段终点为应用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int的开始点)。

对比数据如下:

阶段开始(秒)阶段结束(秒)阶段时长(秒)
优化前同步执行耗时操作3426.2729744923431.7858988375.512924345
优化后异步执行耗时操作4186.4368352464186.9087773350.471942089

可见阶段时长已缩短,故自定义组件生命周期回调接口里避免耗时操作对缩短加载绘制首页阶段耗时是有效的。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值