Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的性能優化(上)

Android的性能優化(上)

編輯:關於Android編程

1.Android UI的渲染機制

當我們感覺到的流暢畫面,需要的畫面幀數要達到40幀到60幀每秒。而一幀的時間大約是16.67ms,換句話說,在1000ms的時間內,16.67ms大約就是現實60幀畫面的單位時間。在Android系統中,系統是通過VSYNC信號觸發對UI的渲染的,如果系統每次渲染的事件都保持在16.67ms以內,那麼我們看到的UI界面將是非常的流暢的,這也就需要我們將所有程序的邏輯都保證在16ms之內,如果不能在16ms內完成繪制,那麼就將造成丟幀的現象。即當前該重繪的幀被未處理完成的邏輯阻塞,例如一次繪制任務耗時20ms,那麼在16ms系統發出的VSYNC信號就無法繪制,該幀就會被丟棄,等待下次信號擦次開始繪制,這就是畫面卡頓的原因。

Android系統提供了檢測UI渲染時間的工具,在“開發者選項中”有“GPU呈現模式分析”,選擇“在屏幕上顯示為條形圖”,如下所示(本測試機為魅族,其他手機可能略有不同):
這裡寫圖片描述

每一個條形圖都包含有三部分,藍色部分表示測量繪制Display List的時間,紅色代表的是OpenGL渲染Display List所需要的時間,黃色代表的是CPU等待GPU處理的時間,中間的綠色橫線代表的是VSYNC時間16ms,需要盡量將所有條形圖都控制在這條綠線之下。

2.overDraw

overDraw表示的就是過度繪制,是指在一幀的時間內(16.67ms)像素被繪制了多次,理論上一個像素每次只繪制一次是最優的,但是由於重疊的布局導致一些像素會被多次繪制,而每次繪制都會對應到CPU的一組繪圖命令和GPU的一些操作,造成CPU和GPU資源的浪費。在系統默認的繪制Activity的背景,如果再給布局繪制了重疊的背景,那麼默認Activity的背景就是無效的過度繪制。

在我們的“開發者選項”中有這樣一個檢測工具“調用GPU過度繪制”,激活該功能之後可以通過界面上的顏色來判斷overDraw的次數。
這裡寫圖片描述
這個工具可以幫助我們檢測當前區域的繪制次數,從而優化界面繪圖層次,盡量增大藍色的區域,減少紅色的區域。

3.優化布局層次

在Android中,系統對View進行測量,布局和繪制時,都是通過對View數的遍歷來進行操作的。如果一個View樹的高度太高,就會嚴重影響到測量,布局和繪制的速度,因此,優化布局的第一個方法就會是降低View樹的高度,Google也在API文檔中建議View樹的高度不宜超過10層。在現在的XML文件的根布局中,我們默認RelativeLayout來替換使用LineraLayout作為默認的根布局,其原因就是通過扁平的RelativeLayout來降低LineraLayout嵌套所產生的布局樹的高度,從而提高UI的渲染速度。

1.使用 include 標簽重用Layout

在一個應用程序的界面上,為了保持風格的統一,很多界面都會存在共通的UI,比如所說Topbar,Bottombar,Actionbar等等,如果在每一個界面上都進行賦值這一段共通的布局代碼,不僅不利於後期代碼的維護,還會增加程序的冗余。這時候就可以使用include標簽來定義一這一個共通的UI。



在該共通的布局中,我將layout_width和layout_height設置為0dp,這樣就迫使調用者在使用時必須對控件的狂傲進行賦值,否者是無法看見該控件的。

下一步就是如何使用該共通的UI布局了。只需要在使用該共通的UI布局文件中使用include標簽的layout屬性對這個共通的UI的ID的引用即可。





    

    

這時候如果我們要對布局中的屬性進行賦值,就要重新覆蓋某一項屬性,進行賦值即可。效果如下:
這裡寫圖片描述

2. 使用ViewStub實現view的延遲加載

使用ViewStub標簽來實現對一個view的引用並且實現延遲加載。ViewStub是一個非常輕量級的組件,它不僅不可視,而且大小為0,下面來演示如何使用ViewStub來進行實現延遲加載的目的。

首先創建一個布局,這個布局在初始化加載時是不需要顯示的,只有在某些情況下才需要進行顯示的,例如查看用戶信息的時候,只有點擊了某一個按鈕時,用戶詳細信息才顯示出來。
當運行程序後,我們發現ViewStub中的布局確實沒有顯示出來,那麼要如何才能重新加載顯示的布局呢?
首先要通過findViewById()方法找到組件ViewStub。

mStub = (ViewStub) findViewById(R.id.vs_viewstub);
接下來就有兩種方式顯示這個view:
VISIBLE
通過調用ViewStub的setVisiblity()方法來顯示這個view.代碼如下:
mStub.setVisibility(View.VISIBLE);
INFLATE
通過調用ViewStub的inflate()方法來顯示這個view.代碼如下:
View inflate = mStub.inflate();

這兩種方式都是可以將ViewStub重新進行展開,顯示引用的布局,而唯一的區別在於就是inflate()可以返回引用的布局,從而可以通過View.findViewById()方法來找到對應的控件。

View inflate = mStub.inflate();
        TextView textview = (TextView) inflate.findViewById(R.id.textview);
        textview.setText("我是點擊後加載的");

注意:不管只用那種方式,一旦ViewStub被設置可見或者是inflate之後,ViewStub就不存在了,不能被反復的inflate,取而代之的就是被inflate的Layout,並將這個Layout的ID重新設置為ViewStub中通過android:inflateId屬性所指定的ID,這也就是為什麼兩次點擊之後會報錯的原因:如下所示:

Caused by: java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent

簡要說明View.GONE和ViewStub標簽的區別是什麼?共同點都是初始時都不會顯示,但是ViewStub標簽只會在顯示時才會去渲染整個布局,而View.GONE,在初始化布局樹的時候就已經添加在布局樹文件中了,相比之下ViewStub的效率會更高。
如下圖所示:
這裡寫圖片描述

4.hierarchyviewer.bat

hierarchyviewer.bat是無法在真機上進行使用的,只能在模擬器上使用或者是原生的模擬器上使用,也就是沒有加密的設備上。當然真機上也是可以用的,可以到github上下載一個開源項目View Server,下面在模擬器上使用hierarchyviewer.bat。
hierarchyviewer.bat位於sdk\tools目錄下,直接雙擊即可啟動,如下:
這裡寫圖片描述

注意:我們在使用hierarchyviewer的時候,一定要是模擬器是打開的,這樣才能在hierarchyviewer中看到我們要顯示的布局文件。
這裡寫圖片描述

下面我們寫一個非常冗余的布局進行顯示文件,代碼如下所示:




    

        

這個布局文件是三層LinearLayout嵌套之後裡面裝了一個button,很顯然這些LinearLayout都是冗余的,利用hierarchyviewer可以打開這個布局文件,如下圖所示:

這裡寫圖片描述
通常情況下,我們只關注ID為content的Framlayout的分支,這也是setContentView()設置的內容,可以很明顯的看出在layout布局文件中(紅色布局),這三層LinearLayout沒有任何的分支,說明是冗余嵌套,可以直接去掉的。

當點擊其中一個view的時候,可以顯示view的繪制情況的,不過第一次點擊的時候各種顯示的事件都是n/a,需要點擊菜單中的Profile Node按鈕重新進行計算,才能回去到繪制信息。在系統的右下方會給出不同顏色的小圓點,用來表示繪制的效率,綠黃紅分別代表的是好中差的繪制效率。
這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved