1# 提升应用冷启动速度 2 3应用启动时延是影响用户体验的关键要素。当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用, 这个启动方式就叫做冷启动。 4 5## 分析应用冷启动耗时 6 7应用冷启动过程大致可分成以下四个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页,如下图: 8 9 10 11>**说明:** 12> 13>关于本文中示例,可参考:[提升应用冷启动速度示例](https://gitee.com/openharmony/applications_app_samples/tree/master/code/DocsSample/Ability/Performance/Startup)。 14 15## 1、缩短应用进程创建&初始化阶段耗时 16 17该阶段主要是系统完成应用进程的创建以及初始化的过程,包含了启动页图标(startWindowIcon)的解码。 18 19### 设置合适分辨率的startWindowIcon 20 21如果启动页图标分辨率过大,解码耗时会影响应用的启动速度,建议启动页图标分辨率不超过256像素*256像素,如下所示: 22 23```json 24 "abilities": [ 25 { 26 "name": "EntryAbility", 27 "srcEntry": "./ets/entryability/EntryAbility.ts", 28 "description": "$string:EntryAbility_desc", 29 "icon": "$media:icon", 30 "label": "$string:EntryAbility_label", 31 "startWindowIcon": "$media:startIcon", // 在这里修改启动页图标,建议不要超过256像素x256像素 32 "startWindowBackground": "$color:start_window_background", 33 "exported": true, 34 "skills": [ 35 { 36 "entities": [ 37 "entity.system.home" 38 ], 39 "actions": [ 40 "action.system.home" 41 ] 42 } 43 ] 44 } 45 ] 46``` 47 48下面使用[SmartPerf](https://gitee.com/openharmony/developtools_smartperf_host)工具,对使用优化前的启动页图标(4096像素\*4096像素)及使用优化后的启动页图标(144像素\*144像素)的启动性能进行对比分析。分析阶段的起点为启动Ability(即`H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility`的开始点),阶段终点为应用第一次接到vsync(即`H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int`的开始点)。 49 50对比数据如下: 51 52| | 阶段开始(秒) | 阶段结束(秒) | 阶段时长(秒) | 53| ---------------------- | -------------- | -------------- | ------------ | 54| 使用优化前的启动页图标 | 5419.484537973 | 5420.327775266 | 0.843237293 | 55| 使用优化后的启动页图标 | 4186.436835246 | 4186.908777335 | 0.471942089 | 56 57可见阶段时长已缩短,故设置合适分辨率的startWindowIcon对缩短应用进程创建&初始化阶段耗时是有效的。 58 59## 2、缩短Application&Ability初始化阶段耗时 60 61该阶段主要是资源加载、虚拟机创建、Application&Ability相关对象的创建与初始化、依赖模块的加载等。 62 63### 减少import的模块 64 65应用代码执行前,应用程序必须找到并加载import的所有模块,应用程序加载的每个额外的第三方框架或者模块都会增加启动时间,耗时长短取决于加载的第三方框架或者模块的数量和大小。推荐开发者尽可能使用系统提供的模块,按需加载,来缩短应用程序的启动耗时。 66 67以下为示例代码: 68 69```ts 70// 优化减少import的模块 71// import ability from '@ohos.ability.ability'; 72// import dataUriUtils from '@ohos.ability.dataUriUtils'; 73// import errorCode from '@ohos.ability.errorCode'; 74// import featureAbility from '@ohos.ability.featureAbility'; 75// import particleAbility from '@ohos.ability.particleAbility'; 76// import wantConstant from '@ohos.ability.wantConstant'; 77// import common from '@ohos.app.ability.common'; 78// import Configuration from '@ohos.app.ability.Configuration'; 79// import contextConstant from '@ohos.app.ability.contextConstant'; 80// import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant'; 81// import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'; 82// import GesturePath from '@ohos.accessibility.GesturePath'; 83// import GesturePoint from '@ohos.accessibility.GesturePoint'; 84// import distributedAccount from '@ohos.account.distributedAccount'; 85// import osAccount from '@ohos.account.osAccount'; 86 87import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 88import UIAbility from '@ohos.app.ability.UIAbility'; 89import Want from '@ohos.app.ability.Want'; 90import window from '@ohos.window'; 91import logger from '../common/Logger'; 92 93export default class EntryAbility extends UIAbility { 94 // ... 95} 96``` 97 98下面使用[SmartPerf](https://gitee.com/openharmony/developtools_smartperf_host)工具,对优化import的模块前(模块数量20个)及优化import的模块后(模块数量5个)的启动性能进行对比分析。分析阶段的起点为启动Ability(即`H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility`的开始点),阶段终点为应用第一次接到vsync(即`H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int`的开始点)。 99 100对比数据如下: 101 102| | 阶段开始(秒) | 阶段结束(秒) | 阶段时长(秒) | 103| ------------------ | -------------- | -------------- | ------------ | 104| 优化import的模块前 | 3042.259391282 | 3046.385614613 | 4.126223331 | 105| 优化import的模块后 | 4186.436835246 | 4186.908777335 | 0.471942089 | 106 107可见阶段时长已缩短,故减少import的模块对缩短Application&Ability初始化阶段耗时是有效的。 108 109## 3、缩短AbilityStage生命周期阶段耗时 110 111该阶段主要是AbilityStage的启动生命周期,执行相应的生命周期回调。 112 113### 避免在AbilityStage生命周期回调接口进行耗时操作 114 115在应用启动流程中,系统会执行AbilityStage的生命周期回调函数。因此,不建议在这些回调函数中执行耗时过长的操作,耗时操作建议通过异步任务延迟处理或者放到其他线程执行。 116 117在这些生命周期回调里,推荐开发者只做必要的操作,详情可以参考:[AbilityStage组件容器](../application-models/abilitystage.md) 118 119以下为示例代码: 120 121```ts 122const LARGE_NUMBER = 10000000; 123const DELAYED_TIME = 1000; 124 125export default class MyAbilityStage extends AbilityStage { 126 onCreate(): void { 127 // 耗时操作 128 // this.computeTask(); 129 this.computeTaskAsync(); // 异步任务 130 } 131 132 onAcceptWant(want: Want): string { 133 // 仅specified模式下触发 134 return 'MyAbilityStage'; 135 } 136 137 computeTask(): void { 138 let count = 0; 139 while (count < LARGE_NUMBER) { 140 count++; 141 } 142 } 143 144 private computeTaskAsync(): void { 145 setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行 146 this.computeTask(); 147 }, DELAYED_TIME); 148 } 149} 150``` 151 152下面使用[SmartPerf](https://gitee.com/openharmony/developtools_smartperf_host)工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即`H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility`的开始点),阶段终点为应用第一次接到vsync(即`H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int`的开始点)。 153 154对比数据如下: 155 156| | 阶段开始(秒) | 阶段结束(秒) | 阶段时长(秒) | 157| ---------------------- | -------------- | -------------- | ------------ | 158| 优化前同步执行耗时操作 | 2124.915558194 | 2127.041354575 | 2.125796381 | 159| 优化后异步执行耗时操作 | 4186.436835246 | 4186.908777335 | 0.471942089 | 160 161可见阶段时长已缩短,故避免在AbilityStage生命周期回调接口进行耗时操作对缩短AbilityStage生命周期阶段耗时是有效的。 162 163## 4、缩短Ability生命周期阶段耗时 164 165该阶段主要是Ability的启动生命周期,执行相应的生命周期回调。 166 167### 避免在Ability生命周期回调接口进行耗时操作 168 169在应用启动流程中,系统会执行Ability的生命周期回调函数。因此,不建议在这些回调函数中执行耗时过长的操作,耗时操作建议通过异步任务延迟处理或者放到其他线程执行。 170 171在这些生命周期回调里,推荐开发者只做必要的操作,下面以UIAbility为例进行说明。关于UIAbility组件生命周期的详细说明,参见[UIAbility组件生命周期](../application-models/uiability-lifecycle.md)。 172 173```ts 174const LARGE_NUMBER = 10000000; 175const DELAYED_TIME = 1000; 176 177export default class EntryAbility extends UIAbility { 178 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 179 logger.info('Ability onCreate'); 180 // 耗时操作 181 // this.computeTask(); 182 this.computeTaskAsync(); // 异步任务 183 } 184 185 onDestroy(): void { 186 logger.info('Ability onDestroy'); 187 } 188 189 onWindowStageCreate(windowStage: window.WindowStage): void { 190 logger.info('Ability onWindowStageCreate'); 191 192 windowStage.loadContent('pages/Index', (err, data) => { 193 if (err.code) { 194 logger.error('Failed to load the content. Cause: ' + JSON.stringify(err) ?? ''); 195 return; 196 } 197 logger.info('Succeeded in loading the content. Data: ' + JSON.stringify(data) ?? ''); 198 }); 199 200 // 耗时操作 201 // this.computeTask(); 202 this.computeTaskAsync(); // 异步任务 203 } 204 205 onWindowStageDestroy(): void { 206 logger.info('Ability onWindowStageDestroy'); 207 } 208 209 onForeground(): void { 210 logger.info('Ability onForeground'); 211 // 耗时操作 212 // this.computeTask(); 213 this.computeTaskAsync(); // 异步任务 214 } 215 216 onBackground(): void { 217 logger.info('Ability onBackground'); 218 } 219 220 computeTask(): void { 221 let count = 0; 222 while (count < LARGE_NUMBER) { 223 count++; 224 } 225 } 226 227 private computeTaskAsync(): void { 228 setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行 229 this.computeTask(); 230 }, DELAYED_TIME); 231 } 232} 233``` 234 235下面使用[SmartPerf](https://gitee.com/openharmony/developtools_smartperf_host)工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即`H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility`的开始点),阶段终点为应用第一次接到vsync(即`H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int`的开始点)。 236 237对比数据如下: 238 239| | 阶段开始(秒) | 阶段结束(秒) | 阶段时长(秒) | 240| ---------------------- | -------------- | -------------- | ------------ | 241| 优化前同步执行耗时操作 | 1954.987630036 | 1957.565964504 | 2.578334468 | 242| 优化后异步执行耗时操作 | 4186.436835246 | 4186.908777335 | 0.471942089 | 243 244可见阶段时长已缩短,故避免在Ability生命周期回调接口进行耗时操作对缩短Ability生命周期阶段耗时是有效的。 245 246## 5、缩短加载绘制首页阶段耗时 247 248该阶段主要是加载首页内容、测量布局、刷新组件并绘制。 249 250### 自定义组件生命周期回调接口里避免耗时操作 251 252自定义组件的生命周期变更会调用相应的回调函数。 253 254aboutToAppear函数会在创建自定义组件实例后,页面绘制之前执行,以下代码在aboutToAppear中对耗时间的计算任务进行了异步处理,避免在该接口执行该耗时操作,不阻塞页面绘制。 255 256以下为示例代码: 257 258```ts 259const LARGE_NUMBER = 10000000; 260const DELAYED_TIME = 1000; 261 262@Entry 263@Component 264struct Index { 265 @State private text: string = ""; 266 private count: number = 0; 267 268 aboutToAppear() { 269 // 耗时操作 270 // this.computeTask(); 271 this.computeTaskAsync(); // 异步任务 272 let context = getContext(this) as Context; 273 this.text = context.resourceManager.getStringSync($r('app.string.startup_text')); 274 } 275 276 build() { 277 Column({ space: 10 }) { 278 Text(this.text).fontSize(50) 279 } 280 .width('100%') 281 .height('100%') 282 .padding(10) 283 } 284 285 computeTask(): void { 286 this.count = 0; 287 while (this.count < LARGE_NUMBER) { 288 this.count++; 289 } 290 let context = getContext(this) as Context; 291 this.text = context.resourceManager.getStringSync($r('app.string.task_text')); 292 } 293 294 // 运算任务异步处理 295 private computeTaskAsync(): void { 296 setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行 297 this.computeTask(); 298 }, DELAYED_TIME); 299 } 300} 301``` 302 303下面使用[SmartPerf](https://gitee.com/openharmony/developtools_smartperf_host)工具,对优化前同步执行耗时操作及优化后异步执行耗时操作的启动性能进行对比分析。分析阶段的起点为启动Ability(即`H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility`的开始点),阶段终点为应用第一次接到vsync(即`H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int`的开始点)。 304 305对比数据如下: 306 307| | 阶段开始(秒) | 阶段结束(秒) | 阶段时长(秒) | 308| ---------------------- | -------------- | -------------- | ------------ | 309| 优化前同步执行耗时操作 | 3426.272974492 | 3431.785898837 | 5.512924345 | 310| 优化后异步执行耗时操作 | 4186.436835246 | 4186.908777335 | 0.471942089 | 311 312可见阶段时长已缩短,故自定义组件生命周期回调接口里避免耗时操作对缩短加载绘制首页阶段耗时是有效的。