UI渲染操做一般依賴於兩個核心組件:CPU與GPU。CPU負責包括Measure,Layout,Record,Execute的計算操做,GPU負責Rasterization(柵格化)操做。 所謂柵格化,就是將那些UI控件(如Button,Bitmap)拆分到不一樣的像素上進行顯示。這是一個很費時的操做,GPU可以加快柵格化的操做。 爲了可以使得App流暢,在Android中咱們有一個16ms準則。這是由於Android平臺的屏幕刷新頻率通常爲60Hz,也就是大概16.6ms一幀。也就是說在16ms內咱們的CPU和GPU必須完成全部的計算,繪製,渲染操做,不然就有可能出現掉幀,卡頓現象,引起性能問題,傷害用戶體驗。 過分繪製(Overdraw)指的是屏幕上的某個像素在同一幀(16ms)的時間內被繪製了過屢次數。 有不少緣由能夠致使丟幀,也許是由於你的layout太過複雜,沒法在16ms內完成測量和佈局,有多是由於你的UI上有層疊太多的繪製單元,還有多是由於動畫執行的次數過多。也有多是是主線程中作了其餘耗時操做,或者線程數量太多。這些都會致使CPU或者GPU負載太重。android
開啓:adb shell setprop debug.hwui.overdraw showshell
關閉:adb shell setprop debug.hwui.overdraw falsecanvas
原色:沒有過分繪製bash
藍色:1 次過分繪製網絡
綠色:2 次過分繪製函數
粉色:3 次過分繪製(不該超過屏幕的四分之一)佈局
紅色:4 次及以上過分繪製(不能出現)性能
(1)當咱們新建一個Activity時,Activity的Theme主題上每每自動有一個背景。可是不少時候這個背景是多餘的,咱們本身使用的控件每每已經設置了背景;優化
在APP Theme中把背景改掉:動畫
<style name="AppTheme" parent="android:Theme.Light.NoTitleBar">
<item name="android:windowBackground">@null</item>
...
</style>
複製代碼
(2)還有不少時候咱們在Activity的佈局文件中的根Layout上就已經設置了background屬性,這樣的狀況下,這個Activity自帶的背景就多餘了。
在Activity的onCreate()中試用如下代碼:
getWindow().setBackgroundDrawable(null);
複製代碼
若是是在Fragment中,就是
getActivity().getWindow().setBackgroundDrawable(null)
複製代碼
咱們平時使用ImageView等相似的顯示圖片的控件時,一般會有一個加載未完成時的佔位圖,不少時候咱們習慣用background屬性進行添加。等到網絡將圖片請求到以後咱們又使用setImageDrawable()設置了圖片,這樣子圖片會覆蓋掉原來的佔位圖,可是Android系統繪製界面時原來的佔位圖和如今的圖片都會被繪製,形成了Overdraw。
就是佔位圖和後來加載到的圖片都使用setImageDrawable()來設置,而不要使用background
使用複雜的Shape有時候也是引發過分繪製的一個因素,好比Stroke,雖然只是描邊,可是會增長整個區域的一層過分繪製。例如,將下面的配置做爲ImageView的背景。
<solid android:color="#FFF8F8F8" />
<stroke
android:dashGap="4dp"
android:dashWidth="2dp"
android:width="2dp"
android:color="#ff1111" />
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<corners android:radius="6dp" />
複製代碼
在有stroke屬性的時候,顯示爲淡紅色,去掉stroke屬性後,顯示爲綠色。
現代佈局使視圖堆疊和分層更加容易。然而,這樣作卻會過分繪製,從而致使性能下降。特別在每個堆疊視圖對象是不透明的場景中,可見和不可見的像素都須要繪製在屏幕上。
若是遇到這類問題,能夠經過優化視圖層次結構來減小重疊的UI對象數量,從而提高性能。
要想扁平化佈局效果,可使用約束性佈局ConstraintLayout。
在自定義控件中,咱們常常會經過onDraw函數繪製一些複雜的形狀、文字、圖片等。可是這些Canvas的繪製函數,每一次調用就會增長一層的繪製,次數越多也就會致使越多的過分繪製。如咱們用以下代碼來自定義繪製圖形,就會存在繪製三次的狀況:
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
int width = getWidth();
int height = getHeight();
Paint paint = new Paint();
paint.setColor(0xFFFFFFFF);
canvas.drawColor(0xFFFFFFFF);
canvas.drawRect(20, 20, width - 20, height - 20, paint);
canvas.drawCircle(width / 2, height / 2, 50, paint);
}
複製代碼
咱們在自定義可重用佈局的時候,都會新建一個文件來存放這個佈局。當咱們在文件中include這個佈局文件的時候,極可能就額外多了一層的佈局。若是這時候使用Merge的話,再使用包含這個的佈局的時候,系統會自動忽略merge層級,把它的子view直接放置與include平級的佈局下。還有一種狀況,例如在LinearLayout等佈局裏面嵌入一個佈局時,恰好這個佈局的根節點也是LinearLayout等佈局的時候,既兩層佈局使用了同一種類型的佈局時,這樣就多了一層沒有用的嵌套,而這個時候若是使用merge根標籤就能夠避免這樣的問題,減小這層無用的嵌套。
不過只能做爲XML佈局的根標籤使用。當Inflate以開頭的佈局文件時,必須指定一個父ViewGroup,而且必須設定attachToRoot爲true。
一些顯示錯誤的界面、加載提示框的界面,ProgressBar等界面,以及用戶不多會觸發的界面,當這些不是必須顯示的佈局都堆在一塊兒時,會對infalte性能、內存等產生不利影響。這個時候用ViewStub標籤就很合適,能夠將這些不經常使用的佈局另外保存爲佈局文件,對應的位置佈局用ViewStub標籤代替。等到真正須要顯示的時候再對ViewStub初始化。由於ViewStub是一個輕量級的View,它是一個不可見,且不佔佈局位置,佔用資源很是小的控件。因此使用ViewStub後,能夠加快Inflate的時間,減小建立的對象數量,從而提高性能和減小內存的佔用。不過ViewStub只能Inflate一次,一旦初始化後該標籤就會被真正的佈局所代替。
一方面減小層級自己就是減小了view的數量,另外像一些場景,文字有大有小,有不一樣顏色,其實用一個TextView就能夠實現,例如能夠藉助Spannable對象實現。不須要使用不少個TextView來實現。
另外,有時咱們發現一個空白區域的佔位也使用了一個view去作,其實用layout_margin屬性或者用其餘方式就能代替掉這個View。