應(yīng)用啟動(dòng)時(shí)延是影響用戶體驗(yàn)的關(guān)鍵要素。當(dāng)應(yīng)用啟動(dòng)時(shí),后臺(tái)沒有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用欺抗, 這個(gè)啟動(dòng)方式就叫做冷啟動(dòng)。
分析應(yīng)用冷啟動(dòng)耗時(shí)
應(yīng)用冷啟動(dòng)過程大致可分成以下四個(gè)階段:應(yīng)用進(jìn)程創(chuàng)建&初始化强重、Application&Ability初始化绞呈、Ability/AbilityStage生命周期、加載繪制首頁间景,如下圖:
1佃声、縮短應(yīng)用進(jìn)程創(chuàng)建&初始化階段耗時(shí)
該階段主要是系統(tǒng)完成應(yīng)用進(jìn)程的創(chuàng)建以及初始化的過程,包含了啟動(dòng)頁圖標(biāo)(startWindowIcon)的解碼拱燃。
設(shè)置合適分辨率的startWindowIcon
如果啟動(dòng)頁圖標(biāo)分辨率過大秉溉,解碼耗時(shí)會(huì)影響應(yīng)用的啟動(dòng)速度力惯,建議啟動(dòng)頁圖標(biāo)分辨率不超過256像素*256像素碗誉,如下所示:
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon", // 在這里修改啟動(dòng)頁圖標(biāo)召嘶,建議不要超過256像素x256像素
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
下面使用 SmartPerf 工具,對(duì)使用優(yōu)化前的啟動(dòng)頁圖標(biāo)(4096像素*4096像素)及使用優(yōu)化后的啟動(dòng)頁圖標(biāo)(144像素*144像素)的啟動(dòng)性能進(jìn)行對(duì)比分析哮缺。分析階段的起點(diǎn)為啟動(dòng)Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility
的開始點(diǎn))弄跌,階段終點(diǎn)為應(yīng)用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int
的開始點(diǎn))。
對(duì)比數(shù)據(jù)如下:
階段開始(秒) | 階段結(jié)束(秒) | 階段時(shí)長(zhǎng)(秒) | |
---|---|---|---|
使用優(yōu)化前的啟動(dòng)頁圖標(biāo) | 5419.484537973 | 5420.327775266 | 0.843237293 |
使用優(yōu)化后的啟動(dòng)頁圖標(biāo) | 4186.436835246 | 4186.908777335 | 0.471942089 |
可見階段時(shí)長(zhǎng)已縮短尝苇,故設(shè)置合適分辨率的startWindowIcon對(duì)縮短應(yīng)用進(jìn)程創(chuàng)建&初始化階段耗時(shí)是有效的铛只。
2、縮短Application&Ability初始化階段耗時(shí)
該階段主要是資源加載糠溜、虛擬機(jī)創(chuàng)建淳玩、Application&Ability相關(guān)對(duì)象的創(chuàng)建與初始化、依賴模塊的加載等非竿。
減少import的模塊
應(yīng)用代碼執(zhí)行前蜕着,應(yīng)用程序必須找到并加載import的所有模塊,應(yīng)用程序加載的每個(gè)額外的第三方框架或者模塊都會(huì)增加啟動(dòng)時(shí)間红柱,耗時(shí)長(zhǎng)短取決于加載的第三方框架或者模塊的數(shù)量和大小承匣。推薦開發(fā)者盡可能使用系統(tǒng)提供的模塊,按需加載锤悄,來縮短應(yīng)用程序的啟動(dòng)耗時(shí)韧骗。
以下為示例代碼:
// 優(yōu)化減少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 工具,對(duì)優(yōu)化import的模塊前(模塊數(shù)量20個(gè))及優(yōu)化import的模塊后(模塊數(shù)量5個(gè))的啟動(dòng)性能進(jìn)行對(duì)比分析零聚。分析階段的起點(diǎn)為啟動(dòng)Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility
的開始點(diǎn))袍暴,階段終點(diǎn)為應(yīng)用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int
的開始點(diǎn))。
對(duì)比數(shù)據(jù)如下:
階段開始(秒) | 階段結(jié)束(秒) | 階段時(shí)長(zhǎng)(秒) | |
---|---|---|---|
優(yōu)化import的模塊前 | 3042.259391282 | 3046.385614613 | 4.126223331 |
優(yōu)化import的模塊后 | 4186.436835246 | 4186.908777335 | 0.471942089 |
可見階段時(shí)長(zhǎng)已縮短隶症,故減少import的模塊對(duì)縮短Application&Ability初始化階段耗時(shí)是有效的容诬。
3、縮短AbilityStage生命周期階段耗時(shí)
該階段主要是AbilityStage的啟動(dòng)生命周期沿腰,執(zhí)行相應(yīng)的生命周期回調(diào)览徒。
避免在AbilityStage生命周期回調(diào)接口進(jìn)行耗時(shí)操作
在應(yīng)用啟動(dòng)流程中,系統(tǒng)會(huì)執(zhí)行AbilityStage的生命周期回調(diào)函數(shù)颂龙。因此习蓬,不建議在這些回調(diào)函數(shù)中執(zhí)行耗時(shí)過長(zhǎng)的操作,耗時(shí)操作建議通過異步任務(wù)延遲處理或者放到其他線程執(zhí)行措嵌。
在這些生命周期回調(diào)里躲叼,推薦開發(fā)者只做必要的操作
以下為示例代碼:
const LARGE_NUMBER = 10000000;
const DELAYED_TIME = 1000;
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
// 耗時(shí)操作
// this.computeTask();
this.computeTaskAsync(); // 異步任務(wù)
}
onAcceptWant(want: Want): string {
// 僅specified模式下觸發(fā)
return 'MyAbilityStage';
}
computeTask(): void {
let count = 0;
while (count < LARGE_NUMBER) {
count++;
}
}
private computeTaskAsync(): void {
setTimeout(() => { // 這里使用setTimeout來實(shí)現(xiàn)異步延遲運(yùn)行
this.computeTask();
}, DELAYED_TIME);
}
}
下面使用 SmartPerf 工具,對(duì)優(yōu)化前同步執(zhí)行耗時(shí)操作及優(yōu)化后異步執(zhí)行耗時(shí)操作的啟動(dòng)性能進(jìn)行對(duì)比分析企巢。分析階段的起點(diǎn)為啟動(dòng)Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility
的開始點(diǎn))枫慷,階段終點(diǎn)為應(yīng)用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int
的開始點(diǎn))。
對(duì)比數(shù)據(jù)如下:
階段開始(秒) | 階段結(jié)束(秒) | 階段時(shí)長(zhǎng)(秒) | |
---|---|---|---|
優(yōu)化前同步執(zhí)行耗時(shí)操作 | 2124.915558194 | 2127.041354575 | 2.125796381 |
優(yōu)化后異步執(zhí)行耗時(shí)操作 | 4186.436835246 | 4186.908777335 | 0.471942089 |
可見階段時(shí)長(zhǎng)已縮短,故避免在AbilityStage生命周期回調(diào)接口進(jìn)行耗時(shí)操作對(duì)縮短AbilityStage生命周期階段耗時(shí)是有效的或听。
4探孝、縮短Ability生命周期階段耗時(shí)
該階段主要是Ability的啟動(dòng)生命周期,執(zhí)行相應(yīng)的生命周期回調(diào)誉裆。
避免在Ability生命周期回調(diào)接口進(jìn)行耗時(shí)操作
在應(yīng)用啟動(dòng)流程中顿颅,系統(tǒng)會(huì)執(zhí)行Ability的生命周期回調(diào)函數(shù)。因此足丢,不建議在這些回調(diào)函數(shù)中執(zhí)行耗時(shí)過長(zhǎng)的操作粱腻,耗時(shí)操作建議通過異步任務(wù)延遲處理或者放到其他線程執(zhí)行。
在這些生命周期回調(diào)里斩跌,推薦開發(fā)者只做必要的操作绍些,下面以UIAbility為例進(jìn)行說明。關(guān)于UIAbility組件生命周期的詳細(xì)說明耀鸦。
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');
// 耗時(shí)操作
// this.computeTask();
this.computeTaskAsync(); // 異步任務(wù)
}
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) ?? '');
});
// 耗時(shí)操作
// this.computeTask();
this.computeTaskAsync(); // 異步任務(wù)
}
onWindowStageDestroy(): void {
logger.info('Ability onWindowStageDestroy');
}
onForeground(): void {
logger.info('Ability onForeground');
// 耗時(shí)操作
// this.computeTask();
this.computeTaskAsync(); // 異步任務(wù)
}
onBackground(): void {
logger.info('Ability onBackground');
}
computeTask(): void {
let count = 0;
while (count < LARGE_NUMBER) {
count++;
}
}
private computeTaskAsync(): void {
setTimeout(() => { // 這里使用setTimeout來實(shí)現(xiàn)異步延遲運(yùn)行
this.computeTask();
}, DELAYED_TIME);
}
}
下面使用 SmartPerf 工具遇革,對(duì)優(yōu)化前同步執(zhí)行耗時(shí)操作及優(yōu)化后異步執(zhí)行耗時(shí)操作的啟動(dòng)性能進(jìn)行對(duì)比分析。分析階段的起點(diǎn)為啟動(dòng)Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility
的開始點(diǎn))揭糕,階段終點(diǎn)為應(yīng)用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int
的開始點(diǎn))萝快。
對(duì)比數(shù)據(jù)如下:
階段開始(秒) | 階段結(jié)束(秒) | 階段時(shí)長(zhǎng)(秒) | |
---|---|---|---|
優(yōu)化前同步執(zhí)行耗時(shí)操作 | 1954.987630036 | 1957.565964504 | 2.578334468 |
優(yōu)化后異步執(zhí)行耗時(shí)操作 | 4186.436835246 | 4186.908777335 | 0.471942089 |
可見階段時(shí)長(zhǎng)已縮短,故避免在Ability生命周期回調(diào)接口進(jìn)行耗時(shí)操作對(duì)縮短Ability生命周期階段耗時(shí)是有效的著角。
5揪漩、縮短加載繪制首頁階段耗時(shí)
該階段主要是加載首頁內(nèi)容、測(cè)量布局吏口、刷新組件并繪制奄容。
自定義組件生命周期回調(diào)接口里避免耗時(shí)操作
自定義組件的生命周期變更會(huì)調(diào)用相應(yīng)的回調(diào)函數(shù)。
aboutToAppear函數(shù)會(huì)在創(chuàng)建自定義組件實(shí)例后产徊,頁面繪制之前執(zhí)行昂勒,以下代碼在aboutToAppear中對(duì)耗時(shí)間的計(jì)算任務(wù)進(jìn)行了異步處理,避免在該接口執(zhí)行該耗時(shí)操作舟铜,不阻塞頁面繪制戈盈。
以下為示例代碼:
const LARGE_NUMBER = 10000000;
const DELAYED_TIME = 1000;
@Entry
@Component
struct Index {
@State private text: string = "";
private count: number = 0;
aboutToAppear() {
// 耗時(shí)操作
// this.computeTask();
this.computeTaskAsync(); // 異步任務(wù)
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'));
}
// 運(yùn)算任務(wù)異步處理
private computeTaskAsync(): void {
setTimeout(() => { // 這里使用setTimeout來實(shí)現(xiàn)異步延遲運(yùn)行
this.computeTask();
}, DELAYED_TIME);
}
}
下面使用 SmartPerf 工具,對(duì)優(yōu)化前同步執(zhí)行耗時(shí)操作及優(yōu)化后異步執(zhí)行耗時(shí)操作的啟動(dòng)性能進(jìn)行對(duì)比分析谆刨。分析階段的起點(diǎn)為啟動(dòng)Ability(即H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility
的開始點(diǎn))塘娶,階段終點(diǎn)為應(yīng)用第一次接到vsync(即H:ReceiveVsync dataCount:24Bytes now:timestamp expectedEnd:timestamp vsyncId:int
的開始點(diǎn))。
對(duì)比數(shù)據(jù)如下:
階段開始(秒) | 階段結(jié)束(秒) | 階段時(shí)長(zhǎng)(秒) | |
---|---|---|---|
優(yōu)化前同步執(zhí)行耗時(shí)操作 | 3426.272974492 | 3431.785898837 | 5.512924345 |
優(yōu)化后異步執(zhí)行耗時(shí)操作 | 4186.436835246 | 4186.908777335 | 0.471942089 |
可見階段時(shí)長(zhǎng)已縮短痊夭,故自定義組件生命周期回調(diào)接口里避免耗時(shí)操作對(duì)縮短加載繪制首頁階段耗時(shí)是有效的刁岸。
寫在最后
如果你覺得這篇內(nèi)容對(duì)你還蠻有幫助,我想邀請(qǐng)你幫我三個(gè)小忙:
- 點(diǎn)贊她我,轉(zhuǎn)發(fā)虹曙,有你們的 『點(diǎn)贊和評(píng)論』迫横,才是我創(chuàng)造的動(dòng)力。
- 關(guān)注小編酝碳,同時(shí)可以期待后續(xù)文章ing??矾踱,不定期分享原創(chuàng)知識(shí)。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)知識(shí)點(diǎn)击敌,請(qǐng)移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu