用開發(fā)《掌上英語》第60篇:應(yīng)用啟動(dòng)優(yōu)化——從 Ability 創(chuàng)建到首頁首屏渲染)
應(yīng)用啟動(dòng)優(yōu)化——從 Ability 創(chuàng)建到首頁首屏渲染一、啟動(dòng)過程的三個(gè)階段HarmonyOS 應(yīng)用的啟動(dòng)過程可以分為三個(gè)階段Ability 創(chuàng)建階段從用戶點(diǎn)擊應(yīng)用圖標(biāo)到onCreate被調(diào)用窗口創(chuàng)建階段從onWindowStageCreate到首幀內(nèi)容加載首屏渲染階段從頁面內(nèi)容加載完成到用戶可交互這三個(gè)階段的總時(shí)長決定了用戶的啟動(dòng)等待時(shí)間。業(yè)界標(biāo)準(zhǔn)是啟動(dòng)時(shí)間不應(yīng)超過 2 秒超過 3 秒用戶流失率顯著上升。二、EntryAbility.onCreate 的初始化在我們的項(xiàng)目中EntryAbility是應(yīng)用的入口 Ability其onCreate方法只做了最必要的初始化exportdefaultclassEntryAbilityextendsUIAbility{onCreate():void{RouterTable.routerInit();}}RouterTable.routerInit()用于初始化路由表。這是啟動(dòng)路徑上必須的步驟——它完成了頁面路由的注冊確保后續(xù)導(dǎo)航操作可以正確找到目標(biāo)頁面。優(yōu)化分析onCreate中只做了一件事這是好的做法。很多開發(fā)者在onCreate中做了大量初始化數(shù)據(jù)庫連接、網(wǎng)絡(luò)請求、讀取配置等導(dǎo)致啟動(dòng)時(shí)間被嚴(yán)重拉長。根據(jù)優(yōu)先級原則必須在啟動(dòng)時(shí)完成的路由注冊、基礎(chǔ)配置→ 放在 onCreate可以在首頁加載后完成的數(shù)據(jù)預(yù)取、登錄檢查→ 放在首頁的aboutToAppear可以在用戶交互時(shí)觸發(fā)的同步數(shù)據(jù)、注冊推送→ 延遲到具體場景三、onWindowStageCreate 的優(yōu)化onWindowStageCreate是窗口創(chuàng)建的階段onWindowStageCreate(windowStage:window.WindowStage):void{try{windowStage.loadContent(pages/Index,(err){if(err.code){UtilLog.error(TAG,Failed to load the content. Cause: %{public}s,JSON.stringify(err));return;}UtilLog.info(TAG,Succeeded in loading the content.);});}catch(e){UtilLog.info(TAG,Ability onWindowStageCreate error);}}這里加載的首頁pages/Index是應(yīng)用的路由入口頁面。這個(gè)頁面的加載速度直接影響首屏展現(xiàn)時(shí)間。優(yōu)化措施首頁頁面輕量化首頁應(yīng)該只加載最核心的 UI 組件不需要一次性加載所有內(nèi)容try-catch 保護(hù)使用異常捕獲防止加載失敗導(dǎo)致白屏異步回調(diào)loadContent是異步操作回調(diào)中才確認(rèn)加載完成四、RouterTable.routerInit() 的作用RouterTable負(fù)責(zé)將頁面 Builder 函數(shù)與路由枚舉值關(guān)聯(lián)exportclassRouterTable{staticrouterInit(){// 關(guān)聯(lián)路由枚舉與頁面 BuilderRouterModule.register(RouterMap.MAIN_PAGE,MainPageBuilder);RouterModule.register(RouterMap.ANSWER_QUESTIONS_PAGE,AnswerQuestionsBuilder);RouterModule.register(RouterMap.WORD_CARD_PAGE,WordCardPageBuilder);// ... 注冊所有頁面}}路由初始化定義了從路由枚舉到頁面組件的映射關(guān)系。這樣當(dāng)調(diào)用RouterModule.push({ url: RouterMap.WORD_CARD_PAGE })時(shí)框架能夠找到對應(yīng)的 Builder 并加載頁面。按需加載策略路由注冊只是注冊了映射關(guān)系并不會(huì)加載頁面組件本身。頁面組件的代碼只有在實(shí)際導(dǎo)航到該頁面時(shí)才會(huì)被加載。這就是按需加載Lazy Loading的機(jī)制——啟動(dòng)時(shí)只注冊映射不加載具體實(shí)現(xiàn)。五、MainPage 首屏 Builder 按需加載首頁MainEntry使用了多個(gè)Builder拆分頁面區(qū)域build(){Column(){Flex({direction:FlexDirection.Column}){this.topBarBuilder();Scroll(){Column({space:10}){this.todayStudyBuilder();this.swiperBuilder();this.functionBarBuilder();this.practiceModeBuilder();this.subjectPracticeBuilder();Blank().layoutWeight(1);}}.scrollBar(BarState.Off).scrollable(ScrollDirection.Vertical).edgeEffect(EdgeEffect.Spring).layoutWeight(1);}}.padding({left:16,right:16}).backgroundColor($r(sys.color.background_secondary)).width(100%).height(100%);}首屏 Builder 的加載策略分區(qū)渲染頂部搜索欄topBarBuilder→ 今日學(xué)習(xí)卡 → 輪播圖 → 功能欄 → 練習(xí)模式 → 學(xué)習(xí)進(jìn)度。每個(gè) Builder 在渲染時(shí)是獨(dú)立的框架可以按順序渲染懶加載內(nèi)容如果某個(gè) Builder 的內(nèi)容需要網(wǎng)絡(luò)數(shù)據(jù)應(yīng)該在aboutToAppear中異步請求而不是阻塞渲染占位狀態(tài)在數(shù)據(jù)加載完成前顯示骨架屏或 Loading 指示器讓用戶感知到頁面正在響應(yīng)在首頁的HomePage組件中aboutToAppear():void{this.propAppStorageV2.connect(Sample,Sample,()newSample())!;}只做了 AppStorageV2 的連接操作沒有發(fā)起網(wǎng)絡(luò)請求或其他耗時(shí)的同步操作。首頁的數(shù)據(jù)如課程列表應(yīng)該在頁面渲染完成后異步加載。六、啟動(dòng)優(yōu)化的具體措施基于上述分析我們可以總結(jié)出以下啟動(dòng)優(yōu)化措施1. 減少同步初始化onCreate中只做路由初始化不做數(shù)據(jù)加載使用單例模式的 Manager如 PreferenceUtil、AudioPlayer在首次訪問時(shí)初始化2. 按需加載頁面組件路由只注冊映射不加載頁面實(shí)現(xiàn)首頁不一次性加載所有子頁面3. 首屏數(shù)據(jù)異步化網(wǎng)絡(luò)請求在aboutToAppear中發(fā)起不阻塞loadContent使用骨架屏優(yōu)化加載體驗(yàn)4. 資源優(yōu)化首頁圖片壓縮到合適的尺寸使用 WebP 格式替代 PNG減少首頁使用的自定義字體文件大小5. 構(gòu)建配置優(yōu)化Release 模式下啟用混淆和壓縮使用增量編譯減少構(gòu)建時(shí)間七、啟動(dòng)性能測量的方法使用 DevEco Studio 的 Profiler 工具可以測量啟動(dòng)性能連接設(shè)備或模擬器打開 Profiler 面板選擇 Launch 類型的跟蹤啟動(dòng)應(yīng)用并觀察從 Ability 創(chuàng)建到首幀渲染的時(shí)間線重點(diǎn)關(guān)注三個(gè)指標(biāo)Ability 創(chuàng)建耗時(shí)onCreate 的執(zhí)行時(shí)間窗口創(chuàng)建耗時(shí)onWindowStageCreate 到 loadContent 回調(diào)首幀渲染耗時(shí)loadContent 完成到頁面內(nèi)容顯示八、總結(jié)應(yīng)用啟動(dòng)優(yōu)化是提升用戶體驗(yàn)的第一道關(guān)卡。從 EntryAbility.onCreate 的路由初始化到 onWindowStageCreate 的頁面加載再到 MainPage 的 Builder 按需渲染每個(gè)階段都有優(yōu)化空間。核心策略是啟動(dòng)時(shí)做最少的事把非必要的初始化延遲到使用時(shí)Lazy Initialization把數(shù)據(jù)加載交由異步任務(wù)處理。這樣用戶能夠最快看到首屏內(nèi)容后續(xù)的數(shù)據(jù)填充和功能加載在用戶感知之外完成。