01
項目背景
“愛奇藝奇巴布”是愛奇藝爲0-8歲孩子和家長定製化設計的寓教於樂平臺,爲兒童量身打造精緻的觀看體驗,精彩內容解鎖寓教於樂新方式。爲兒童提供優質動畫內容的同時,我們更關注APP用戶體驗。在產品交互設計上我們立足兒童視角,把內容瀏覽和觀影做到做到簡約易用。奇巴布APP整體界面簡約、導航清晰、播放流暢,以極致的設計理念榮獲2018年德國紅點傳達設計獎。
02
問題現狀
卡頓原因
屏幕刷新率由硬件決定,通常是 60Hz/S,或者由 OS 和硬件協調動態調整刷新率。當程序通過 CPU、GPU 渲染畫面的過程中,耗時超過一次刷新間隔,就會使得屏幕畫面沒有更新,導致卡頓現象產生,影響用戶體驗。
Feed卡頓問題分析
使用性能較差的手機滑動Feed流,通過Xcode-Instruments工具分析在滑動過程中具體耗時分佈情況。截取代表性性能分析圖,如下:
-
Feed中存在較多不同樣式Card,多種Card類的合計初始化耗時較長; -
Feed中有各種圖片,這些本地圖片資源在主線程讀取和渲染,有性能提升空間; -
Feed滑動中圖片庫(基於SDWebImage二次開發)在讀取磁盤緩存文件過程中耗時較長,且在主線程中做讀取操作; -
Feed滑動過程中播放器開播與停播耗時較長; -
Feed滑動過程中Card區塊曝光引發頻繁Pingback投遞,整體耗時較長。
03
解決方案
Card數據解析與渲染異步處理
使用QoS的NSQualityOfServiceUserInitiated創建自定義隊列,當前設備CPU活躍核心數和自定義最大核心數比較,獲得結果設置隊列上限。通過限制併發數量減少多個線程頻繁切換帶來CPU資源損耗,避免GCD API頻繁創建線程。Card數據解析和佈局計算、播放器內核初始化、圖片和文本渲染都使用該自定義隊列來處理。
首頁Card預加載
在奇巴布Feed列表中前幾屏幕業務數據大多爲固定推薦內容組合,Card類型繁多無法複用,因此預先加載前幾屏不同Card實例是提高性能的一種技術手段。具體解決方案如下:
預加載策略:
APP每次冷啓動時,總體策略是以最快速度展示內容給用戶,縮短啓動時間。首頁Feed接口在發送網絡請求過程中有網絡延遲,在服務端數據傳送到本地之前加載本地磁盤緩存的上次啓動時Feed流JSON數據。利用磁盤中持久化的JSON數據,解析出JSON對應的Card類,將常用的Card類名緩存到內存,以備在合適的時機初始化Card實例,以備後續滑動Feed時直接讀取Card實例,從而避免在滑動過程中初始化。
預加載時機的判別與執行:
在用戶啓動APP的瞬間,會存在大量異步業務操作搶佔CPU資源。所以需要尋找CPU閒置且用戶沒有手勢操作時預加載Card。監測與執行大體實現邏輯是:通過向主線程RunLoop添加Observer監聽DefaultMode,監聽作用的時間點爲線程進入休眠之前或RunLoop即將退出。當方法回調觸發時,意味着用戶沒有滑動或者滑動結束,在回調方法中做預加載。
本地圖片預解碼
Feed中各種本地圖片
-
預加載策略: 在APP首頁渲染完成後,異步執行統計常用Card中依賴的角標和佔位圖,提前生成Bitmap, 並加載到內存。Hook圖片調用方法[UIImage imageNamed:],在後續調用[UIImage imageNamed:] 方法時將省去I/O和解碼過程,並通過以圖片名鍵值匹配方式存儲避免多次緩存。 -
解碼方案:
-
圖片庫讀取優化
-
其他優化
-
針對問題現狀中第4個問題:Feed滑動過程中播放器開播與停播耗時較長,解決辦法是在滑動時避免播放器的初始化,避免播放器的停播,維持播放狀態與滑動前一致。另外在Card停播時顯性的調用停止加載數據API,防止播放器在後臺異步加載數據。 -
針對問題現狀中第5個問題:Card區塊曝光引發頻繁Pingback投遞耗時較長,且在主線程中操作。解決思路是滑動時對統計方法限流、降低調用頻次。曝光精度會有非常小的下降,但在可接受範圍內。
04
項目總結
技術總結
以UML時序圖彙總優化技術點,如下圖:
項目收益
使用Apple Xcode工具Scroll Hitch Rate監測優化效果,優化後每秒滑動掛起降低至1.4ms,遠低於Apple對滑動流暢的標準5ms/s,即使在性能較差的低端機上滑動也非常流暢,用戶體驗有較大提升。
本文分享自微信公衆號 - 愛奇藝技術產品團隊(iQIYI-TP)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。