android 過分繪製

1.概述

  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

2.GPU過渡繪製調試

開啓:adb shell setprop debug.hwui.overdraw showshell

關閉:adb shell setprop debug.hwui.overdraw falsecanvas

3.過分繪製的分級:

原色:沒有過分繪製bash

藍色:1 次過分繪製網絡

綠色:2 次過分繪製函數

粉色:3 次過分繪製(不該超過屏幕的四分之一)佈局

紅色:4 次及以上過分繪製(不能出現)性能

4.避免過分繪製

4.1去掉Activity的冗餘的背景

(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)
複製代碼

4.2 ImageView的background和setImageDrawable()重疊

  咱們平時使用ImageView等相似的顯示圖片的控件時,一般會有一個加載未完成時的佔位圖,不少時候咱們習慣用background屬性進行添加。等到網絡將圖片請求到以後咱們又使用setImageDrawable()設置了圖片,這樣子圖片會覆蓋掉原來的佔位圖,可是Android系統繪製界面時原來的佔位圖和如今的圖片都會被繪製,形成了Overdraw。

就是佔位圖和後來加載到的圖片都使用setImageDrawable()來設置,而不要使用background

4.3 減小Drawable的複雜Shape

  使用複雜的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屬性後,顯示爲綠色。

4.4使視圖層級扁平化

  現代佈局使視圖堆疊和分層更加容易。然而,這樣作卻會過分繪製,從而致使性能下降。特別在每個堆疊視圖對象是不透明的場景中,可見和不可見的像素都須要繪製在屏幕上。

  若是遇到這類問題,能夠經過優化視圖層次結構來減小重疊的UI對象數量,從而提高性能。

要想扁平化佈局效果,可使用約束性佈局ConstraintLayout。

4.5自定義控件中onDraw函數的正確使用

  在自定義控件中,咱們常常會經過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);
    
  }
複製代碼

4.6經過Merge標籤減小View樹層次

  咱們在自定義可重用佈局的時候,都會新建一個文件來存放這個佈局。當咱們在文件中include這個佈局文件的時候,極可能就額外多了一層的佈局。若是這時候使用Merge的話,再使用包含這個的佈局的時候,系統會自動忽略merge層級,把它的子view直接放置與include平級的佈局下。還有一種狀況,例如在LinearLayout等佈局裏面嵌入一個佈局時,恰好這個佈局的根節點也是LinearLayout等佈局的時候,既兩層佈局使用了同一種類型的佈局時,這樣就多了一層沒有用的嵌套,而這個時候若是使用merge根標籤就能夠避免這樣的問題,減小這層無用的嵌套。

  不過只能做爲XML佈局的根標籤使用。當Inflate以開頭的佈局文件時,必須指定一個父ViewGroup,而且必須設定attachToRoot爲true。

4.7經過ViewStub標籤優化佈局

  一些顯示錯誤的界面、加載提示框的界面,ProgressBar等界面,以及用戶不多會觸發的界面,當這些不是必須顯示的佈局都堆在一塊兒時,會對infalte性能、內存等產生不利影響。這個時候用ViewStub標籤就很合適,能夠將這些不經常使用的佈局另外保存爲佈局文件,對應的位置佈局用ViewStub標籤代替。等到真正須要顯示的時候再對ViewStub初始化。由於ViewStub是一個輕量級的View,它是一個不可見,且不佔佈局位置,佔用資源很是小的控件。因此使用ViewStub後,能夠加快Inflate的時間,減小建立的對象數量,從而提高性能和減小內存的佔用。不過ViewStub只能Inflate一次,一旦初始化後該標籤就會被真正的佈局所代替。

4.8減小不須要的View

  一方面減小層級自己就是減小了view的數量,另外像一些場景,文字有大有小,有不一樣顏色,其實用一個TextView就能夠實現,例如能夠藉助Spannable對象實現。不須要使用不少個TextView來實現。

另外,有時咱們發現一個空白區域的佔位也使用了一個view去作,其實用layout_margin屬性或者用其餘方式就能代替掉這個View。

相關文章
相關標籤/搜索