(鴻蒙)應(yīng)用啟動(dòng)優(yōu)化-應(yīng)用啟動(dòng)框架AppStartup

1.概述

??在我們應(yīng)用啟動(dòng)時(shí),通常需要初始化一些啟動(dòng)任務(wù),如果我們將所有的任務(wù)都放置在應(yīng)用主模塊(也就是entry類型的Module)它的UIAbility組件的onCreate生命周期中,那么任務(wù)只能在主線程中依次執(zhí)行,這樣就會(huì)影響應(yīng)用的啟動(dòng)速度,當(dāng)啟動(dòng)任務(wù)過多時(shí),任務(wù)之間復(fù)雜的依賴關(guān)系還會(huì)使得代碼難以維護(hù)。官方提供了一種簡(jiǎn)單高效的應(yīng)用啟動(dòng)框架AppStartup。

2.應(yīng)用啟動(dòng)流程

  • 進(jìn)程啟動(dòng)過程
    1. 由系統(tǒng)服務(wù)通過孵化進(jìn)程拉起應(yīng)用主進(jìn)程并創(chuàng)建出相應(yīng)的運(yùn)行環(huán)境。
    2. 應(yīng)用再根據(jù)實(shí)際情況請(qǐng)求系統(tǒng)服務(wù)。
    3. 啟動(dòng)應(yīng)用所需的其他進(jìn)程。
      注意:每個(gè)應(yīng)用至多并存三類進(jìn)程(主進(jìn)程、Extension類進(jìn)程、Render進(jìn)程),應(yīng)用中所有的進(jìn)程都是由系統(tǒng)創(chuàng)建和管理的。
  • 模塊啟動(dòng)順序
    1. 首先拉起應(yīng)用的入口模塊,該模塊加載時(shí)會(huì)創(chuàng)建一個(gè)AbilityStage實(shí)例
      (這里我們可以理解為Android中的Application),可以對(duì)該模塊進(jìn)行初始化等操作。
    2. 模塊初始完成后,會(huì)拉起相應(yīng)的入口UIAbility(這里我們可以理解為Android中的MainActivity)。
    3. UIAbility加載完成后會(huì)生成一個(gè)WindowStage類實(shí)例并與之綁定(這里我們可以理解為Android中的PhoneWindow)。WindowStage發(fā)揮了應(yīng)用進(jìn)程內(nèi)窗口管理器的作用,UIAbility通過它持有一個(gè)窗口,在該窗口上加載出首個(gè)ArkUI頁(yè)面(這里我們可以理解為Android中的布局文件R.layout.xxx),從而在設(shè)備上呈現(xiàn)。
  • 啟動(dòng)流程總結(jié)
    ??系統(tǒng)服務(wù)孵化應(yīng)用進(jìn)程,拉起應(yīng)用主進(jìn)程,其次拉起應(yīng)用入口模塊,此時(shí)就會(huì)實(shí)例化AbilityState實(shí)例,拉起應(yīng)用的入口UIAbility,執(zhí)行其生命周期,當(dāng)onCreate執(zhí)行完成后會(huì)執(zhí)行onWindowStageCreate會(huì)創(chuàng)建WindowState實(shí)例與之綁定,它是應(yīng)用進(jìn)程的窗口管理器,可以加載ArkUI頁(yè)面。

3.AppStartup介紹

??它是一種簡(jiǎn)單高效的應(yīng)用啟動(dòng)方式,可以支持任務(wù)的異步啟動(dòng),加快應(yīng)用啟動(dòng)速度。同時(shí),通過在一個(gè)配置文件中統(tǒng)一設(shè)置多個(gè)啟動(dòng)任務(wù)的執(zhí)行順序以及依賴關(guān)系,讓執(zhí)行啟動(dòng)任務(wù)的代碼變得更加簡(jiǎn)潔清晰、容易維護(hù)。

功能特性

  • 支持任務(wù)的異步啟動(dòng)。
  • 配置文件統(tǒng)一配置任務(wù)的執(zhí)行順序及依賴關(guān)系。
  • 支持自動(dòng) / 手動(dòng) 執(zhí)行啟動(dòng)任務(wù)。

執(zhí)行流程圖

image.png

使用限制

  • 啟動(dòng)框架只支持在entry類型的Module下的UIAbility中使用。
  • 啟動(dòng)任務(wù)之間不允許存在循環(huán)依賴。

使用流程

1. 定義啟動(dòng)框架配置文件:在資源文件目錄下創(chuàng)建啟動(dòng)框架配置文件、添加啟動(dòng)任務(wù)的配置信息,并在module.json5配置文件中引用。
    1. 在應(yīng)用主模塊(即entry類型的Module)的“resources/base/profile”路徑下,新建啟動(dòng)框架配置文件。文件名可以自定義,本文以"startup_config.json"為例。
    {
      "startupTasks": [
        {
          "name":"StartupTask_001",                                //啟動(dòng)任務(wù)名稱
          "srcEntry": "./ets/startup/StartupTask_001.ets",         //啟動(dòng)任務(wù)對(duì)應(yīng)的文件路徑
          "dependencies": [                                        //啟動(dòng)任務(wù)依賴的其他啟動(dòng)任務(wù)的類名數(shù)組
            "StartupTask_002"
          ],
          "runOnThread": "taskPool",                               //執(zhí)行初始化所在的線程,默認(rèn)主線程,mainThread:在主線程中執(zhí)行。- taskPool:在異步線程中執(zhí)行
          "waitOnMainThread": false                                //主線程是否需要等待啟動(dòng)框架執(zhí)行
        },
        {
          "name":"StartupTask_002",
          "srcEntry": "./ets/startup/StartupTask_002.ets",
          "dependencies": [],
          "runOnThread": "taskPool",
          "waitOnMainThread": false
        },
        {
          "name":"StartupTask_003",
          "srcEntry": "./ets/startup/StartupTask_003.ets",
          "dependencies": [],
          "excludeFromAutoStart": true,                            //設(shè)置啟動(dòng)模式,默認(rèn)為false,  true:手動(dòng)模式, false:自動(dòng)模式
          "runOnThread": "taskPool",
          "waitOnMainThread": false
        }
      ],
      "configEntry": "./ets/startup/StartupConfig.ets"
    }
    
  • 2.在啟動(dòng)框架配置文件startup_config.json中,依次添加各個(gè)啟動(dòng)任務(wù)的配置信息。
      {
        "module": {
          "name": "entry",
          "type": "entry",
          "abilities": [
            {
              "name": "EntryAbility",
              "srcEntry": "./ets/entryability/EntryAbility.ets",
              ...
            }
          ]
    
          "appStartup": "$profile:startup_config"     //配置AppStartUp的啟動(dòng)項(xiàng)任務(wù)文件
        }
      }
    
2. 設(shè)置啟動(dòng)參數(shù):在啟動(dòng)參數(shù)文件中,設(shè)置超時(shí)時(shí)間和啟動(dòng)任務(wù)的監(jiān)聽器等參數(shù)。
    1. 創(chuàng)建啟動(dòng)參數(shù)配置文件,使用StartupConfigEntry接口實(shí)現(xiàn)啟動(dòng)框架公共參數(shù)的配置,包括超時(shí)時(shí)間和啟動(dòng)任務(wù)的監(jiān)聽器等參數(shù),其中需要用到如下接口:
    • StartupConfig:用于設(shè)置任務(wù)超時(shí)時(shí)間和啟動(dòng)框架的監(jiān)聽器。
    • StartupListener:用于監(jiān)聽啟動(dòng)任務(wù)是否執(zhí)行成功。
     export default class MyStartupConfigEntry extends StartupConfigEntry{
        onConfig(): StartupConfig {
          console.info('ych' , `onConfig`)
          //監(jiān)聽啟動(dòng)任務(wù)執(zhí)行的回掉,成功/失敗
          let onCompletedCallback = (error: BusinessError<void>) => {
            console.info('ych' , `onCompletedCallback`)
            if (error) {
              console.error('ych' , `onCompletedCallback error: ${error.message}`)
            } else {
              console.info('ych' , `onCompletedCallback: success.`)
            }
          };
          let startupListener: StartupListener = {
            'onCompleted': onCompletedCallback
          };
    
          // 任務(wù)參數(shù)配置
          let config: StartupConfig = {
            'timeoutMs': 5000,                  // 任務(wù)超時(shí)時(shí)間 
            'startupListener': startupListener  // 啟動(dòng)任務(wù)監(jiān)聽器
          };
          return config;
        }
      }
    
3. 為每個(gè)待初始化組件添加啟動(dòng)任務(wù):通過實(shí)現(xiàn)StartupTask接口,啟動(dòng)框架將會(huì)按順序執(zhí)行初始化流程。
注意:
*     1. 啟動(dòng)任務(wù)必須實(shí)現(xiàn) StartupTask 類
*     2. 由于StartupTask采用了 Sendable 協(xié)議(線程間通信對(duì)象),在繼承該接口時(shí),必須添加Sendable注解。
*     3. 如果任務(wù)不是應(yīng)用創(chuàng)建時(shí)必須初始化,那么我們可以使用手動(dòng)初始化,直接調(diào)用
*       3.1.
*        try {
*           startupManager.run(["StartupTask_003"]).then(()=>{
*              console.error('ych' , `StartupTask_003 啟動(dòng)完成`)
*           }).catch((err:BusinessError)=>{
*              console.error('ych' , `StartupTask_003 啟動(dòng)失敗  ${err.message}`)
*           })
*        }catch (error){
*          console.error('ych' , `StartupTask_003 啟動(dòng)失敗  ${error.message}`)
*        }
*      3.2.需要在resource/config/startup.json中配置該任務(wù)為非必須任務(wù)。也就是 "excludeFromAutoStart": true
@Sendable
export default class StartupTask_001 extends StartupTask{
  constructor() {
    super();
  }

  /**
   * TODO: 啟動(dòng)任務(wù)初始化。當(dāng)該任務(wù)依賴的啟動(dòng)任務(wù)全部執(zhí)行完畢,即onDependencyCompleted完成調(diào)用后,才會(huì)執(zhí)行init方法對(duì)該任務(wù)進(jìn)行初始化。
   *  總結(jié):
   *    1.如果該任務(wù)無依賴任務(wù),則不會(huì)執(zhí)行onDependencyCompleted方法,直接執(zhí)行init方法。
   *    2.如果該任務(wù)有依賴任務(wù),則先執(zhí)行onDependencyCompleted方法,再執(zhí)行init方法。
   */
  async init(context: common.AbilityStageContext){
    this.myStartupTask_001()
    return "StartupTask_001"
  }

  onDependencyCompleted(dependence: string, result: Object): void {
    console.error('ych', `依賴的任務(wù)名稱為:${dependence}  --- 結(jié)果:${result.valueOf()}`,
      dependence, JSON.stringify(result));
  }


  myStartupTask_001(){
    console.error('ych' , `StartupTask_001開始初始化`)
  }
}
使用注意:
  • 1. 啟動(dòng)任務(wù)必須實(shí)現(xiàn) StartupTask 類
    1. 由于StartupTask采用了 Sendable 協(xié)議(線程間通信對(duì)象),在繼承該接口時(shí),必須添加Sendable注解。
    1. 如果任務(wù)不是應(yīng)用創(chuàng)建時(shí)必須啟動(dòng),那么我們可以使用手動(dòng)啟動(dòng),直接調(diào)用

      • 3.1.手動(dòng)啟動(dòng)任務(wù)
      try {
        startupManager.run(["StartupTask_001"]).then(()=>{
            console.error('ych' , `StartupTask_001 啟動(dòng)完成`)
         }).catch((err:BusinessError)=>{
            console.error('ych' , `StartupTask_001 啟動(dòng)失敗  ${err.message}`)
         })
      }catch (error){
        console.error('ych' , `StartupTask_001 啟動(dòng)失敗  ${error.message}`)
      }
      
      • 3.2.需要在resource/config/startup.json中配置該任務(wù)為非必須任務(wù)。也就是 "excludeFromAutoStart": true
        {
          "startupTasks": [
          {
              "name":"StartupTask_001",                              
              "srcEntry": "./ets/startup/StartupTask_001.ets",      
              "dependencies": [],
              "runOnThread": "taskPool",     
              "excludeFromAutoStart": true,     //設(shè)置啟動(dòng)模式,默認(rèn)為false,  true:手動(dòng)模式, false:自動(dòng)模式
              "waitOnMainThread": false                               
          },
          "configEntry": "./ets/startup/StartupConfig.ets"
        }
        
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容