HarmonyOS APP性能優(yōu)化之提升應(yīng)用冷啟動(dòng)速度

應(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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拴事,隨后出現(xiàn)的幾起案子沃斤,更是在濱河造成了極大的恐慌,老刑警劉巖刃宵,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衡瓶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡牲证,警方通過查閱死者的電腦和手機(jī)哮针,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坦袍,“玉大人十厢,你說我怎么就攤上這事∥嫫耄” “怎么了蛮放?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奠宜。 經(jīng)常有香客問我包颁,道長(zhǎng),這世上最難降的妖魔是什么压真? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任娩嚼,我火速辦了婚禮,結(jié)果婚禮上滴肿,老公的妹妹穿的比我還像新娘岳悟。我一直安慰自己,他們只是感情好泼差,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布竿音。 她就那樣靜靜地躺著,像睡著了一般拴驮。 火紅的嫁衣襯著肌膚如雪春瞬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天套啤,我揣著相機(jī)與錄音宽气,去河邊找鬼随常。 笑死,一個(gè)胖子當(dāng)著我的面吹牛萄涯,可吹牛的內(nèi)容都是我干的绪氛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涝影,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼枣察!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燃逻,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤序目,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后伯襟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猿涨,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年姆怪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叛赚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稽揭,死狀恐怖俺附,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溪掀,我是刑警寧澤昙读,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站膨桥,受9級(jí)特大地震影響蛮浑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜只嚣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一沮稚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧册舞,春花似錦蕴掏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至藐石,卻和暖如春即供,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背于微。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國打工逗嫡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留青自,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓驱证,卻偏偏與公主長(zhǎng)得像延窜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抹锄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容