減緩 PageView 動畫加上 Table 造成的卡頓 — 問題篇

減緩 PageView 動畫加上 Table 造成的卡頓 — 問題篇

更新於 發佈於 閱讀時間約 4 分鐘


raw-image

最近我們新增了一個顯示球員詳細資訊的頁面,當我們完成第一版程式碼,開始調整細節時,我們發現了畫面滑動似乎不太順暢。

raw-image

每個球員訊息彈跳視窗是靜態,外層使用了 PageView 加上一些的特效,使得畫面在滑動時會頻繁的 setState,造成了整個彈跳視窗卡頓,使用者體驗不佳,就像遊戲效能不好一樣會掉幀,嚴重一點可能會讓人不舒服。今天就來分享如何快速有效的解決這個問題吧。

開啟 Profile 模式

首先,想要有效的解決問題,釐清問題是第一步。為了要了解我們畫面卡頓的問題根源,我們使用 Flutter 提供的 DevTools 並在實體手機上運行 Profile 模式。Profile 模式是讓 App 運行效能接近 Release 模式同時又能搜集運行資訊的一種模式。當我們執行程式並開起 DevTools 之後,可以觀察到 App 運行時,每一個 Frame 效能到底如何。

Dev tools

在 Dev Tools 面板中,可以發現在大多數 Frame 中,UI phase 與 Raster phase 都花了很多時間,這通常表示問題可能有很多個,但是我們今天先研究 UI phase 花過久時間的問題吧。

raw-image

在面板中清楚看到了 Build 和 Layout 畫面的操作各花了多久時間,我們可以初步了解問題可能發生在哪邊,但是只有這些資訊,顯然不夠我們解決問題。

啟用 Track Widget Builds

為了更深入了解問題出在哪邊,我們可以在 Dev Tools 的右上角打開 Enhance Tracing,並且勾選 Track Widget Builds,這個功能可以提供更詳細的時間,提供每一個 Widget 在每一個 Frame 中所花費的時間。

raw-image

觀察 Widget Build 火焰圖

當我們啟用 Track Widget Build 之後,我們再繼續操作一下手機,讓手機繼續執行幾個 Frame,我們就能這些新產生的報告找到 Timeline Events,在 Timeline Events 中, DevTools 顯示在這個 Frame 中 Build Widget 所花費的時間,能更直觀地看到時間到底花在哪個 Widget 上了。

分析問題

從火焰圖中我們可以得知,PlayerInfoGameLogView 花費的時間佔了很大一部份比例,而且每一個 Frame 都是這種狀況。這表示畫面滑動的時候,每一個 Frame 都在重新建立這個 Widget。

雖然我們滑動需要頻繁的 setState,畫面其實是不變的,數值並不會在滑動過程中有變化,應該要可以使用重複使用之前已經 Build 好的 Widget,但是顯然 Flutter 不這麼認為,而是辛苦的每一個 Frame 都Rebuild 新的 Widget。

小結

在分析問題中,我們發現問題的癥結點,當我們滑動 PageView 時,Flutter 會重複且完整的建立每一個 Page,花費許多時間去 Build Widget,在下一篇文章中,我們會利用 dartpad 寫一個有問題的範例,並在這個範例中探討解決方案,有興趣的朋友可以先嘗試看看。

avatar-img
保羅的軟體開發日常
0會員
19內容數
分享各種軟體開發技巧與心得
留言
avatar-img
留言分享你的想法!
透過簡單的範例,介紹 Container 的排版問題。文中用簡單的方式帶你深入原始碼,探索你不知道的 Container 行為。
本文探討了 Element 更新機制,並分析 Row + Expanded 與 AnimatedSize 無法正常運作的元因。最後提供了兩種解決方案:使用 Expanded 並將 flex 設為 0,或使用 GlobalObjectKey。
本文深入分析了 Row 的佈局邏輯及其與 Flexible 和 Expanded 的互動,帶領讀者深入了解 Row 的運作機制。
透過簡單的範例,介紹 Container 的排版問題。文中用簡單的方式帶你深入原始碼,探索你不知道的 Container 行為。
本文探討了 Element 更新機制,並分析 Row + Expanded 與 AnimatedSize 無法正常運作的元因。最後提供了兩種解決方案:使用 Expanded 並將 flex 設為 0,或使用 GlobalObjectKey。
本文深入分析了 Row 的佈局邏輯及其與 Flexible 和 Expanded 的互動,帶領讀者深入了解 Row 的運作機制。