用開發(fā)《掌上英語》第79篇:@ReusableV2 全局復(fù)用池:單詞卡片列表的極致性能優(yōu)化)
ReusableV2 全局復(fù)用池單詞卡片列表的極致性能優(yōu)化一、組件復(fù)用的痛點(diǎn)在 HarmonyOS 5.0 中Reusable裝飾器已經(jīng)支持組件的局部復(fù)用——在同一個(gè)List或Grid中離開屏幕的 item 可以被回收其組件實(shí)例被后續(xù)進(jìn)入屏幕的 item 復(fù)用。這種復(fù)用可以有效減少組件創(chuàng)建和銷毀的開銷提升列表滑動(dòng)性能。但局部復(fù)用有一個(gè)固有局限復(fù)用池是列表級(jí)別的。也就是說List A回收的 item 組件實(shí)例只能被List A再次使用不能被List B使用。在我們的英語學(xué)習(xí) App 中CourseHomePage中的單詞卡片和WordCardPage中的單詞卡片是同樣的 UI 組件但由于它們屬于不同的頁面和不同的列表在 5.0 中無法跨列表復(fù)用。當(dāng)用戶從首頁導(dǎo)航到單詞卡片頁時(shí)所有卡片組件需要重新創(chuàng)建造成明顯的延遲。HarmonyOS 6.0 的ReusableV2裝飾器引入了全局復(fù)用池的概念。組件實(shí)例不再綁定到某個(gè)列表而是被放入全局共享的復(fù)用池中任何頁面、任何列表都可以從池中獲取可復(fù)用的組件實(shí)例。二、Reusable 與 ReusableV2 的區(qū)別對(duì)比維度Reusable5.0ReusableV26.0復(fù)用范圍列表級(jí)別同 List/Grid 內(nèi)全局級(jí)別跨列表、跨頁面復(fù)用池管理系統(tǒng)自動(dòng)管理可配置池大小和策略aboutToReuse 回調(diào)支持支持增強(qiáng)復(fù)用池命中率低僅在同一列表內(nèi)高全局共享使用場景單一長列表多個(gè)列表共用同一組件類型從使用方式上看兩者非常相似都需要在自定義組件上添加裝飾器并實(shí)現(xiàn)aboutToReuse回調(diào)。區(qū)別在于ReusableV2需要額外配置復(fù)用池的大小和初始容量。三、全局復(fù)用池配置與大小控制使用ReusableV2時(shí)需要為組件配置一個(gè)全局復(fù)用池。復(fù)用池的設(shè)置包括兩個(gè)關(guān)鍵參數(shù)poolSize復(fù)用池的最大容量即最多在池中保留多少組件實(shí)例。initSize預(yù)創(chuàng)建的組件實(shí)例數(shù)量在頁面加載時(shí)就提前創(chuàng)建好。// 配置單詞卡片的全局復(fù)用池ComponentV2 ReusableV2({poolSize: 20,initSize: 5 })exportstructReusableWordCard { Param Require wordCard: WordCard; Param Require isFlipped: boolean; State cardRotation: number 0; aboutToReuse(params: Recordstring,object): void {// 重置卡片狀態(tài)this.cardRotation 0; this.wordCard params.wordCardasWordCard; this.isFlipped params.isFlippedasboolean; } build(){Column(){Text(this.wordCard.word).fontSize(24).fontWeight(FontWeight.Bold);Text(this.wordCard.phonetic).fontSize(14).opacity(0.7);Text(this.wordCard.translation).fontSize(16).margin({ top:8}); } .width(100%) .padding(16) .borderRadius(16).backgroundColor(Color.White); } }poolSize的設(shè)置建議根據(jù)實(shí)際使用場景確定。在我們的 App 中同時(shí)最多可能出現(xiàn)的單詞卡片數(shù)量為CourseHomePage一次展示 1 張卡片單張翻轉(zhuǎn)模式。WordCardPage一次展示 1 張卡片滑動(dòng)切換模式。首頁推薦單詞區(qū)域展示 3-5 張推薦卡片。MyWrongPage錯(cuò)題本每行展示 2-3 張錯(cuò)題卡片可見區(qū)域約 6-10 張。綜合考慮復(fù)用池容量設(shè)置為 15-20 即可覆蓋所有并發(fā)的卡片渲染需求。設(shè)置過大會(huì)浪費(fèi)內(nèi)存設(shè)置過小則復(fù)用命中率不足。initSize設(shè)為 5 意味著在 App 啟動(dòng)后預(yù)創(chuàng)建 5 個(gè)卡片組件實(shí)例等待使用減少了用戶首次看到卡片時(shí)的創(chuàng)建延遲。四、aboutToReuse 回調(diào)的數(shù)據(jù)重置aboutToReuse是復(fù)用組件的關(guān)鍵生命周期回調(diào)。當(dāng)一個(gè)組件從復(fù)用池中被取出、準(zhǔn)備復(fù)用時(shí)系統(tǒng)會(huì)調(diào)用此方法開發(fā)者需要在此方法中重置組件的狀態(tài)確保復(fù)用的組件不會(huì)殘留上一個(gè) item 的數(shù)據(jù)。在ReusableWordCard中需要在aboutToReuse中處理以下狀態(tài)重置Param 參數(shù)更新將新的wordCard和isFlipped數(shù)據(jù)賦值到組件中。動(dòng)畫狀態(tài)重置如果上一個(gè)單詞的卡片處于翻轉(zhuǎn)狀態(tài)cardRotation 180需要重置為 0否則新的單詞一出現(xiàn)就是翻轉(zhuǎn)的。音頻狀態(tài)重置如果上一個(gè)單詞正在播放音頻需要停止并釋放音頻資源。內(nèi)部狀態(tài)清理如有展開/折疊、選中態(tài)等內(nèi)部狀態(tài)全部恢復(fù)到默認(rèn)值。aboutToReuse(params: Recordstring,object):void{// 1. 重置動(dòng)畫this.cardRotation 0;this.showTranslation false;// 2. 停止可能正在播放的音頻AudioPlayer.getInstance().stop();// 3. 更新數(shù)據(jù)this.wordCard params.wordCardasWordCard;this.isFlipped params.isFlippedasboolean;// 4. 重置其他內(nèi)部狀態(tài)this.isFavorite false; }需要注意的是aboutToReuse中的操作應(yīng)當(dāng)盡量輕量避免執(zhí)行復(fù)雜的計(jì)算或 I/O 操作。如果需要加載數(shù)據(jù)如異步加載單詞的詳細(xì)例句應(yīng)該在build()方法中根據(jù)wordCard的數(shù)據(jù)按需加載而非在aboutToReuse中阻塞等待。五、首頁推薦單詞與今日復(fù)習(xí)共用卡片復(fù)用池復(fù)用池的威力在于共享。在我們的英語學(xué)習(xí) App 中有多處地方展示單詞卡片CourseHomePage核心單詞學(xué)習(xí)頁展示一張大卡片用戶翻轉(zhuǎn)查看釋義。WordCardPage答題模式中的單詞卡片用戶滑動(dòng)切換。MainPage首頁推薦單詞區(qū)域展示 3 張推薦卡片。MainPage首頁今日復(fù)習(xí)區(qū)域展示 5 張待復(fù)習(xí)卡片。MyWrongPage錯(cuò)題卡片列表。在 ReusableV2 模式下所有這 5 處地方的單詞卡片共享同一個(gè)全局復(fù)用池。當(dāng)用戶在CourseHomePage學(xué)完單詞返回首頁時(shí)CourseHomePage的卡片實(shí)例不會(huì)銷毀而是進(jìn)入全局復(fù)用池。當(dāng)首頁的今日復(fù)習(xí)需要展示卡片時(shí)直接從池中獲取已經(jīng)創(chuàng)建好的實(shí)例只需要通過aboutToReuse更新數(shù)據(jù)即可。這種跨頁面、跨列表的共享復(fù)用是 ReusableV2 相對(duì)于 Reusable 的最大優(yōu)勢。在 App 使用過程中組件實(shí)例的總數(shù)量會(huì)快速趨于穩(wěn)定等于復(fù)用池大小不會(huì)隨著頁面切換而持續(xù)創(chuàng)建和銷毀。六、復(fù)用池命中率分析復(fù)用池的優(yōu)化效果可以用命中率來衡量——即從池中成功獲取已有組件的次數(shù)占總請(qǐng)求次數(shù)的比例。命中率越高說明復(fù)用效果越好。在我們的場景中命中率可以用以下公式估算命中率 (復(fù)用池大小 × 平均頁面停留時(shí)間)/(組件創(chuàng)建頻率 × 頁面切換頻率)在典型使用流程中首頁 → 課程學(xué)習(xí) → 錯(cuò)題本 → 首頁單詞卡片的復(fù)用路徑如下**首頁推薦單詞**首次請(qǐng)求池為空創(chuàng)建 3 個(gè)實(shí)例。命中率 0%。進(jìn)入 CourseHomePage請(qǐng)求 1 個(gè)卡片池中 3 個(gè)可用命中 1 個(gè)。命中率 100%。返回首頁CourseHomePage 的 1 個(gè)實(shí)例回收到池池中現(xiàn)有 3 個(gè)。進(jìn)入錯(cuò)題本請(qǐng)求 6 個(gè)錯(cuò)題卡片將單詞卡片復(fù)用為錯(cuò)題卡片。命中 3 個(gè)創(chuàng)建 3 個(gè)。隨著使用時(shí)間的推移池中的實(shí)例數(shù)量會(huì)穩(wěn)定在復(fù)用池設(shè)定的上限20 個(gè)后續(xù)所有的卡片請(qǐng)求都從池中獲取命中率接近 100%。這意味著在整個(gè) App 的使用過程中創(chuàng)建卡片組件的總次數(shù)不會(huì)超過復(fù)用池的容量無論用戶切換了多少個(gè)頁面、瀏覽了多少單詞。七、實(shí)踐建議先對(duì)高頻核心卡片啟用復(fù)用在推行 ReusableV2 時(shí)建議按照核心 → 擴(kuò)展的順序第一階段僅對(duì)WordCard組件啟用 ReusableV2。這是 App 中最高頻使用的組件5 個(gè)頁面共用同一類型。優(yōu)先優(yōu)化這個(gè)組件收益最大、改動(dòng)范圍最小。第二階段對(duì)MyWrongItem錯(cuò)題卡片和MyCollectionItem收藏卡片啟用復(fù)用。這兩個(gè)組件雖然不如單詞卡片高頻但在錯(cuò)題本和收藏夾中被多次復(fù)用。第三階段對(duì)通用的列表 item 組件如Banner、CourseCoreBar啟用復(fù)用。在每個(gè)階段啟用后使用 DevEco Studio 的 Profiler 工具觀察列表滾動(dòng)的幀率和組件創(chuàng)建數(shù)量。如果幀率穩(wěn)定在 55fps 以上、組件創(chuàng)建數(shù)量趨于穩(wěn)定達(dá)到池上限后不再增長說明復(fù)用效果已達(dá)到預(yù)期。八、總結(jié)ReusableV2 全局復(fù)用池將組件復(fù)用的范圍從列表級(jí)擴(kuò)展到了應(yīng)用級(jí)使得不同頁面、不同列表中的同一類型組件可以共享實(shí)例。對(duì)于以單詞卡片為核心展示形態(tài)的英語學(xué)習(xí) App這不僅減少了組件創(chuàng)建銷毀的內(nèi)存開銷更重要的是消除了頁面切換時(shí)的組件創(chuàng)建延遲。全局復(fù)用池 卡片翻轉(zhuǎn)動(dòng)畫的 GPU 加速兩者配合讓 App 的卡片使用體驗(yàn)既流暢又省資源。