如何做一個流暢的UI 組內分享記錄

一銘發表於2017-12-13

前提 最近做了一次組內分享,這個 idea 來自去滬江的分享會聽到的,學到了一些,也分享給組內的小夥伴.

###什麼是卡頓? 這件事要從RunLoop開始,RunLoop是一個60FPS[注1]的回撥,也就是說每16.7ms繪製一次螢幕,也就是我們需要在這個時間內完成緩衝區建立,緩衝區內容的繪製這些是CPU的工作;然後把緩衝區交給GPU渲染,這裡包括了多個View的拼接(Compositing),紋理的渲染(Texture)等等,最後Display到螢幕上。但是如果你在16.7ms內做的事情太多,導致CPU,GPU無法在指定時間內完成指定的工作,那麼就會出現卡頓現象,也就是丟幀。 ####使用者能感受到的卡頓: 1.頁面的 FPS 降低,滑動時有困頓; 2.頁面卡死,無法響應; 3.主執行緒的 Runloop 執行了很久; ####可能是什麼原因導致了卡頓: 1.死鎖:主執行緒拿到鎖 A, 需要鎖 B;子執行緒拿到鎖 B,需要鎖 A,相互等待導致死鎖; 2.搶鎖:主執行緒需要讀取 DB,子執行緒在插入資料. 3.主執行緒大量 IO. 4.主執行緒大量計算. 5.大量的UI、複雜的UI繪製.

###螢幕的成像原理

幻燈片06.jpg
iOS的顯示系統是由 Vsync 脈衝訊號驅動的, Vsync 脈衝訊號由硬體時鐘生成,大約每秒鐘發出60次, iPhone 採用的雙緩衝,安卓在4.1之後是三緩衝.[注2] 通常來說,計算機系統中的 CPU,GPU, 顯示器的協同工作是: 1.CPU 計算好顯示內容提交到 GPU; 2.GPU 渲染完成後將渲染結果放入 Back Buffer(第一緩衝區); 3.然後等待顯示器發的垂直同步訊號(VSync),Frame Buffer(第二緩衝區)copy 第一緩衝區的顯示內容 4.螢幕經過數模轉換顯示出來. 所以要避免卡頓就要在16.7ms 內完成第一緩衝區的建立,所以我們所能做的優化絕大部分要在CPU,GPU這兩部分. ###如何使頁面流暢 ####從CPU入手: 先看看CPU要做的事情: 1.物件建立; 2.佈局計算; 3.複雜演算法; 4.AutoLayout; 5.文字圖片的繪製; 這僅僅是列出一小部分CPU的工作,可以嘗試如何從以上幾條來優化: 1.物件建立:物件的建立會分配記憶體、調整屬性、檔案的 IO等操作,這些都比較佔 CPU的資源,如果一個 物件的建立會分配記憶體、調整屬性、甚至還有讀取檔案等操作

####從GPU入手: GPU的職責:根據CPU提供的內容進行渲染,輸出到螢幕上. 在 Core Animation的組成部分中, OpenGL ES 是直接呼叫 GPU 進行渲染的.它有兩種渲染方式:

  • On-Screen Rendering
  • Off-Screen Rendering:是指GPU在當前螢幕緩衝區以外新開闢一個緩衝區進行渲染操作.

#####為什麼離屏渲染會帶來效能消耗? 1.建立新的緩衝區 2.多次上下文切換 #####離屏渲染的觸發方式 1.光柵化(shouldRasterize)[注3] 2.遮罩(masks) 3.陰影(shadows) 4.不透明(opacity) 5.圓角

###更多可優化點:

  • 非同步繪製
  • 演算法優化
  • AsyncDisplayKit
  • ...

###參考文件

###Q&A

###注: 注1.FPS是影象領域中的定義,是指畫面每秒傳輸幀數,通俗來講就是指動畫或視訊的畫面數。FPS是測量用於儲存、顯示動態視訊的資訊數量。每秒鐘幀數愈多,所顯示的動作就會愈流暢

注2.通常來說,計算機系統中 CPU、GPU、顯示器是以上面這種方式協同工作的。CPU 計算好顯示內容提交到 GPU,GPU 渲染完成後將渲染結果放入幀緩衝區,隨後視訊控制器會按照 VSync 訊號逐行讀取幀緩衝區的資料,經過可能的數模轉換傳遞給顯示器顯示

注3..當一個列表檢視中出現大量圓角的 CALayer,並且快速滑動時,可以觀察到 GPU 資源已經佔滿,而 CPU 資源消耗很少。這時介面仍然能正常滑動,但平均幀數會降到很低。為了避免這種情況,可以嘗試開啟 CALayer.shouldRasterize 屬性,但這會把原本離屏渲染的操作轉嫁到 CPU 上去。

相關文章