【Android 性能優化】佈局渲染優化 ( 過渡繪製 | 背景設置產生的過度繪製 | Android 系統的渲染優化 | 自定義佈局渲染優化 )





一、 背景設置產生的過度繪製



1. 背景設置產生的過度繪製 :


① 組件背景 : 每個組件每設置一次背景 , 該組件的區域就會增加一層繪製 , 如 LinearLayout 線性佈局設置背景顏色 , TextView 設置背景顏色 , 都會增加該組件區域內的過渡繪製 ;

② 佈局背景 : 佈局文件總的背景 , 會增加一次 GPU 繪製 ;

③ 主題背景 : Activity 界面的主題背景 , 會增加一次 GPU 繪製 ;



2. 組件背景設置策略 : 不要隨便爲組件添加背景 , 添加一次背景 , 就增加一次 GPU 繪製 ;

不要隨意給佈局中的 UI 組件設置背景 , 能不設置背景的就不設置背景 , 如 ImageView 組件 , 設置一張圖片 , 會增加一次繪製 , 如果再給該 ImageView 組件設置背景顏色 , 那麼又會增加一次繪製 , 那麼該 ImageView 組件肯定過渡繪製了 ;





二、 Android 系統的渲染優化



【Android 性能優化】佈局渲染優化 ( CPU 與 GPU 架構分析 | 安卓佈局顯示流程 | 視覺與幀率分析 | 渲染超時卡頓分析 | 渲染過程與優化 ) 博客中分析了圖像渲染的 16 毫秒過程中

  • CPU 渲染
  • CPU 傳遞數據到 GPU
  • GPU 渲染

是三大耗時操作 , 上述分析的背景過渡繪製 , 是從減少 GPU 渲染時間角度出發 , 降低圖像渲染時間 ;


CPU 傳遞數據給 GPU 非常耗時 ;


下面分析是從 降低 CPU 傳遞數據到 GPU 時間 角度出發 , 進行的優化 , 這部分優化是由 Android 系統完成的 ;



1. 透明組件數據傳遞


Android 系統做了如下自動優化操作 , 當組件的背景是透明的 , 那麼 CPU 將該組件轉爲多維向量圖片 ( 多邊形和紋理組成 ) 時發現該組件是透明的 , 該組件的圖像信息就不會傳遞給 GPU 進行渲染 , 從而減少了 CPU 向 GPU 傳遞的數據大小 ; 之前講到過 , CPU 向 GPU 傳遞數據也是一個非常耗時的操作 , 因此該優化 , 也降低了組件渲染的時間 ;


透明組件擺放處理 : CPU 不傳遞這些組件到 GPU 中 , 但是在佈局中仍然正常擺放 ;



2. GPU 存儲機制


1. GPU 存儲紋理機制 : GPU 中的顯存可以存儲紋理資源 , 即多維向量圖形資源 , 在渲染時 , 可以直接使用該存儲的資源 , 不用每次都讓 CPU 傳遞數據過來 ;


2. CPU 傳遞主題資源給 GPU 機制 : 傳遞主題資源是一次性傳遞 , 主題中的 背景 , 顏色 , 圖片 ( Bitmap , Drawable ) 等資源都打包存儲在了多維向量圖形 ( 多邊形 和 紋理 ) 中 , 傳遞給 GPU 進行渲染 , GPU 每次進行渲染時直接從存儲區域取出這些資源 , 進行渲染 , 不再依賴 CPU 實時傳遞 ;

這種變化較少的資源 , 適合一次性加載 , 應用或界面的主題資源基本不會改變 ;


3. 普通的 UI 組件資源 : 如果是普通的 UI 組件 , 那麼就不能只加載一次了 , 需要每次渲染時 , CPU 都要將組件加載到內存 , 並轉成的多維向量圖形 , 最後傳遞給 GPU ;



3. Android 7.0 之後的優化機制


Android 7.0 之後的優化機制 :


① 7.0 系統優化前 : Android 7.0 之前調用 UI 組件的 invalidate 方法 , 組件會回調 onLayout , onMeasure 和 onDraw 方法 ;

② 7.0 系統優化後 : Android 7.0 之後調用 UI 組件的 invalidate 方法 , 組件不會回調 onLayout 和 onMeasure 方法 , 只會調用 onDraw 方法 ;

③ 7.0 系統優化後工作機制 : 在 GPU 中緩存 UI 組件對應的多維向量圖形 ( 紋理 ) , 當該組件位置或顏色等外觀發生變化時 , 就會通知 CPU , 重新進行加載 , 如 onLayout 擺放 , onMeasure 測量 , 並轉爲多維向量圖 ( 紋理 ) , 傳遞給 GPU 進行渲染 ; 如果沒有發生變化 , 調用 invalidate 方法 , 只會在 GPU 中重新渲染 ; 不會重新 擺放 ( onLayout ) 與 測量 ( onMeasure ) ;





三、 自定義佈局渲染優化



1. 自定義組件過度繪製問題描述 : 自定義控件 , 在自定義的 onDraw 方法中 , 繪製多張圖片 , 如果圖片之間產生重疊 , 重疊繪製的部分就出現了過度繪製 ;



2. 自定義組件繪製原則 :


① 兩張圖片 : 圖片 AA圖片 BB ;

在這裏插入圖片描述

② 圖片覆蓋 : 當圖片 AA 被圖片 BB 覆蓋時 , 只繪製圖片 AA 顯示的部分區域 , 圖片 AA 被圖片 BB 覆蓋的部分不再繪製 ;

在這裏插入圖片描述

③ 圖片 AA 只繪製沒有被覆蓋的部分 : 只在圖片 AA 顯示的區域繪製圖片 AA 的區域 , 如下圖黃色框中的區域 ;

在這裏插入圖片描述



3. 實現上述圖片 AA 在 Canvas 畫布上繪製部分圖片方式 :


① 完整畫布 : onDraw 函數中的 Canvas canvas 參數是完整的畫布 ;

② 取出圖片 AA 繪製部分的 Canvas 畫布 : 這部分畫布就是上圖中 , 被黃色框框起來的畫布 , 傳入的四個參數是黃色矩形框的左上右下參數 , 注意剪切之前先保存畫布 ;

// 剪切畫布前 , 先保存畫布 , 之後還要恢復回去
canvas.save();
// 剪切畫布
canvas.clipRect(left, top, right, bottom);

③ 在剪切後的畫布中繪製圖片 AA : 在剪切後的畫布中 , 繪製圖片 AA , 注意繪製完成後 , 恢復畫布 ;

// 在剪切後的畫布中 , 繪製圖片 A
canvas.drawBitmap(...);
// 繪製完畢後 , 恢復畫布
canvas.restore();

④ 繪製效果 : 上述代碼的繪製效果大概就是繪製了部分圖片 AA , 下圖中的下面的部分圖片 AA 展示 ;

在這裏插入圖片描述



3. clipRect 函數原型 : 剪切畫布 , 獲取 Canvas 完整畫布的子畫布 , 傳入左 , 上 , 右 , 下 , 四個值 , 將畫布剪切出來 ;

    public boolean clipRect(float left, float top, float right, float bottom) {
        return nClipRect(mNativeCanvasWrapper, left, top, right, bottom,
                Region.Op.INTERSECT.nativeInt);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章