產品需求和性能問題 canvas
在IG中,feed是由圖片,視頻和文字組成的。對於每一個圖片和視頻,咱們須要展現對應的圖片說明和5條最近的評論。因爲用戶一般經過圖片說明來說書圖片背後的故事,這些圖片說明一般是大段複雜的文字,甚至可能包含連接和emoji表情。
渲 染這種複雜文本的主要問題在於它滾動時對性能的影響。在Android中,文本的渲染是很慢的。即便在一個像Nexus 5這樣的新設備上,一段有十幾行復雜文本的圖片說明的初始繪製時間可能會達到50ms,而其文本的measure階段就須要30ms。這些都發生在UI線 程,在滾動時會致使app跳幀。 緩存
Android有不少用於文字展現的控件,但實際上,他們都用text.Layout進行渲染。例如,TextView會將String轉化爲一個text.Layout對象,並經過canvas API將它繪製到屏幕上。 app
因爲text.Layout須要在構造函數中測量文本的高度,所以它的建立效率不高。緩存text.Layout和複用text.Layout實例 能夠節省這部分時間。Android的TextView控件並無提供設置TextLayout的方法,可是添加一個這樣的方法並不困難: 編輯器
使用自定義的view來手動繪製text.Layout會提高其性能:TextView是一個包含大量特性的通用控件。若是咱們只須要在屏幕上渲染靜態的,可點擊的文本,事情就簡單多了: 函數
咱們能夠不用從SpannableStringBuilder轉化到String。根據你的文本中是否包含連接,底層的TextView可能會複製一份你的字符串,這須要分配一些內存。 性能
咱們能夠一直使用StaticLayout,這比DynamicLayout要稍微快一些。 測試
咱們能夠避免使用TexView中其餘的邏輯: 監聽文本修改的邏輯,展現嵌入drawable的邏輯,繪製編輯器的邏輯以及彈出下拉列表的邏輯。 優化
經過使用TextLayoutView,咱們能夠緩存和複用text.Layout,從而避免了每次調用TextView的setText(CharSequence c)方法時都要花費20ms來建立它。 ui
因爲咱們肯定會在下載評論後展現他們,一個簡單的改進是在下載它們後就準備好text.Layout的緩存。
spa
在能夠設置text.Layout緩存後,咱們的到來常數級的測量(measure)和綁定(binding)時間。可是初次繪製的時間仍然很長。50ms的繪製時間可能會致使明顯的卡頓。
這50ms中的大部分被用於測量文本高度以及產生文字符號。這些都是CPU操做。爲了提高文本渲染速度,Android在ICS中引入了 TextLayoutCache用於緩存這些中間結果。TextLayoutCache是一個LRU緩存,緩存的key是文本。若是查詢緩存時命中,文本 的繪製速度會有很大提高。
在咱們的測試中,這種緩存能夠將繪製時間從30ms-50ms減小到2ms-6ms。
爲了更好的提高繪製性能,咱們能夠在繪製文本到屏幕前準備好這個緩存。咱們的思路是在一塊屏幕外的canvas上虛擬的繪製這些文本。這樣在咱們繪製文本到屏幕前,TextLayoutCache就已經在一個背景線程中被準備好了。
默認狀況下,TextLayoutCache的大小爲0.5M,這足以緩存十幾張圖片的評論。咱們決定在用戶中止滑動時準備緩存,咱們向用戶滑動的方向提早緩存5個圖片的評論。在任什麼時候候,咱們都至少在任何一個方向上緩存了5個圖片的評論。
在應用了全部的這些優化後,掉幀狀況減小了60%,而卡頓的狀況減小了50%。