Android 渲染優化
原來我的代碼寫得這麽爛!
為什麽優化
卡頓現象,由於復雜的布局或界面過度繪制未能在每幀16ms內完成導致的。
復雜的布局
Android系統每隔16ms發出VSYNC信號,觸發對UI進行渲染,要每次渲染都成功,這樣就必須達到流暢的畫面所需要的60fps,否則會發生丟幀的現象,丟幀越多,用戶明確感到卡頓。
補充:
1、fps,每秒顯示幀數,幀率測量單位(frames per second);
2、為什麽是60fps(16ms=1000/60)?因為人眼與大腦之間的協作無法感知超過60fps的畫面更新。
過度繪制
Overdraw(過度繪制)是指系統在單個渲染幀中多次繪制屏幕上的像素。例如,如果我們有一堆堆疊的UI卡,不可見的UI也在做繪制的操作,這樣會浪費大量的CPU和GPU資源。
補充:
渲染操作通常依賴於兩個核心組件:CPU與GPU。CPU負責包括Measure,Layout,Record,Execute的計算操作,GPU負責Rasterization(柵格化)操作。
如何檢測
Show GPU Overdraw
打開Show GPU Overdraw選項進行觀察是否存在過度繪制。
步驟:
設置 -> 開發者選項 -> 調試GPU過度繪制 ->顯示過度繪制區域。
對比一張Overdraw的參考圖,分別有藍色,淡綠,淡紅,深紅代表了4種不同程度的Overdraw情況:
藍色: 意味著overdraw 1倍,像素繪制了兩次;
綠色: 意味著overdraw 2倍,像素繪制了三次;
深紅: 意味著overdraw 4倍,像素繪制了五次或者更多。
我們的目標就是盡量減少紅色Overdraw,看到更多的藍色區域。
Profile GPU Rendering
打開Profile GPU Rendering,顯示每幀畫面所需要渲染的時間。
步驟:
設置 -> 開發者選項 -> GPU呈現模式分析 -> 在屏幕上顯示為條形圖
界面上會滾動顯示垂直的柱狀圖來表示每幀畫面所需要渲染的時間,柱狀圖越高表示花費的渲染時間越長。中間有一根綠色的橫線,代表16ms,我們需要確保每一幀花費的總時間都低於這條橫線,這樣才能夠避免出現卡頓的問題。
Hierarchy Viewer
用Hierarchy Viewer工具檢查Activity中的布局是否過於復雜
步驟:
Tools -> Android -> Android Device Monitor。
打開Hierarchy Viewe:
啟動Android Device Monitor成功之後,在新的的窗口中點擊切換視圖圖標,選擇Hierarchy Viewe:
使用Hierarchy Viewer:
其實中帶有紅色或×××的點代表速度較慢的View。
友情提示:
APP先運行起來再使用Android Device Monitor,建議用模擬器,手機可能讀不到內容。
TraceView
使用TraceView來觀察CPU執行情況,使用詳見:性能分析工具 Android TraceView。
優化
刪除不必要的布局背景
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/backgroundColor" android:orientation="vertical"> <com.wuxiaolong.pullloadmorerecyclerview.PullLoadMoreRecyclerView android:id="@+id/pullLoadMoreRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent"/></LinearLayout>
如果這裏PullLoadMoreRecyclerView也設置背景色是沒有必要了。
另外,使用Android一些自帶的主題,window被默認添加一個純色的背景,theme中添加android:windowbackground=”null”除掉或添加自己需要的背景色,減少渲染。
優化布局層次
通過優化視圖層次結構,以減少重疊的UI對象的數量來提高性能。
這裏得糾正我一個錯誤,我平時不想使用RelateLayout,是因為不想每個都命名id,命名是件很頭疼的事,所以我更多使用了LinearLayout布局。為了提高性能,還是盡量多使用RelativeLayout吧。
使用include、merge、ViewStub
1、include布局重用;
2、merge減少視圖層級;
3、ViewStub標簽是當你需要時才會加載
詳細介紹見:Android抽象布局——include、merge 、ViewStub
自定義組件的onDraw()
1、避免大量創建臨時對象,比如String,以免頻繁觸發GC;
2、考慮使用canvas.clipRect()繪制需要被繪制的區域。
ListView
1、考慮使用ViewHolder;
2、或者RecycleView來代替
Lint
Lint是一個代碼掃描工具,能夠幫助我們識別代碼結構存在的問題。在布局文件上運行lint工具來搜索可能的視圖層次結構優化是一種很好的做法。
步驟:Android Studio,Analyze -> Inspect Code。
布局信息將顯示在Android> Lint> Performance下:
要查看更多詳細信息,您可以單擊每個項目來展開它,並在屏幕右側的窗格中查看更多信息。
lint規則:
Use compound drawables - A LinearLayout which contains an ImageView and a TextView can be more efficiently handled as a compound drawable.
Merge root frame - If a FrameLayout is the root of a layout and does not provide background or padding etc, it can be replaced with a merge tag which is slightly more efficient.
Useless leaf - A layout that has no children or no background can often be removed (since it is invisible) for a flatter and more efficient layout hierarchy.
Useless parent - A layout with children that has no siblings, is not a ScrollView or a root layout, and does not have a background, can be removed and have its children moved directly into the parent for a flatter and more efficient layout hierarchy.
Deep layouts - Layouts with too much nesting are bad for performance. Consider using flatter layouts such as RelativeLayout or GridLayout to improve performance. The default maximum depth is 10.
Lint除了layout優化,還能檢查編碼、可訪問性等問題。
Android 渲染優化