Android 性能優化之減少UI過度繪製

来源:https://www.cnblogs.com/jiangzhishan/archive/2018/07/20/9341658.html
-Advertisement-
Play Games

什麼是過度繪製(OverDraw) 在多層次重疊的UI結構裡面,如果不可見的UI也在做繪製的操作,會導致某些像素區域被繪製了多次。這樣就會浪費大量的CPU以及GPU資源。過度繪製最直觀的影響就是會導致APP卡頓。還好系統有提供GPU過度繪製調試工具會在屏幕上用不同的顏色,來表明一個像素點位被重覆繪製 ...


什麼是過度繪製(OverDraw)


在多層次重疊的UI結構裡面,如果不可見的UI也在做繪製的操作,會導致某些像素區域被繪製了多次。這樣就會浪費大量的CPU以及GPU資源。過度繪製最直觀的影響就是會導致APP卡頓。還好系統有提供GPU過度繪製調試工具會在屏幕上用不同的顏色,來表明一個像素點位被重覆繪製的次數。

怎樣開啟GPU過度繪製調試工具?

1.點擊進入“設置”;
2.點擊進入“開發者選項”
3.選中“調試GPU過度繪製”
4.選中“顯示過度繪製區域”

此時,你會註意到屏幕的顏色變化了,別緊張。切換到你的應用,現在我們開始瞭解怎麼通過改善佈局來解決過度繪製問題。

屏幕上不同的顏色代表著什麼?

1.原色沒有被過度繪製 – 這部分的像素點只在屏幕上繪製了一次。
2.藍色1次過度繪製– 這部分的像素點只在屏幕上繪製了兩次。
3.綠色2次過度繪製 – 這部分的像素點只在屏幕上繪製了三次。
4.粉色3次過度繪製 – 這部分的像素點只在屏幕上繪製了四次。
5.紅色4次過度繪製 – 這部分的像素點只在屏幕上繪製了五次。

怎麼解決應用過度繪製?

由上面的知識,我們知道要解決過度繪製。即是要儘量減少屏幕上的紅色區域,增加屏幕上的藍色和綠色區域。我們的目標是要控制界面最多被過度繪製2次(不出現粉色和紅色)。

1.合理選擇控制項容器
既然overdraw是因為重覆繪製了同一片區域的像素點,那我們首先想到的是解決佈局問題。Android提供的Layout控制項主要包括LinearLayout、TableLayout、FrameLayout、RelativeLayout(這裡我們不考慮AbsoluteLayout)。同一個界面我們可以使用不同的容器控制項來表達,但是各個容器控制項描述界面的複雜度是不一樣的。一般來說LinearLayout最易,RelativeLayout較複雜。但是尺有所短,寸有所長,LinearLayout只能用來描述一個方向上連續排列的控制項,容易導致佈局文件嵌套太深,不符合佈局扁平化的設計原理。而RelativeLayout幾乎可以用於描述任意複雜度的界面。但是表達能力越強的容器控制項,性能往往略低一些,因為RelativeLayout主要在onMeasure和onLayout階段會耗費更多時間。綜上所述:LinearLayout易用,效率高,表達能力有限。RelativeLayout複雜,表達能力強,但是效率稍遜。所以當某一界面在使用LinearLayout並不會比RelativeLayout帶來更多的控制項數和控制項層級時,我們要優先考慮LinearLayout。但是要根據實際情況來做一個取捨,在保證性能的同時儘量避免OverDraw。


2.去掉window的預設背景
當我們使用了Android自帶的一些主題時,window會被預設添加一個純色的背景,這個背景是被DecorView持有的。當我們的自定義佈局時又添加了一張背景圖或者設置背景色,那麼DecorView的background此時對我們來說是無用的,但是它會產生一次Overdraw,帶來繪製性能損耗。去掉window的背景可以在onCreate()中setContentView()之後調用
getWindow().setBackgroundDrawable(null);

或者在theme中添加
android:windowbackground="null";


3.去掉其他不必要的背景
有時候為了方便會先給Layout設置一個整體的背景,再給子View設置背景,這裡也會造成重疊,如果子View寬度mach_parent,可以看到完全覆蓋了Layout的一部分,這裡就可以通過分別設置背景來減少重繪。再比如如果採用的是selector的背景,將normal狀態的color設置為“@android:color/transparent",也同樣可以解決問題。這裡只簡單舉兩個例子,我們在開發過程中的一些習慣性思維定式會帶來不經意的Overdraw,所以開發過程中我們為某個View或者ViewGroup設置背景的時候,先思考下是否真的有必要,或者思考下這個背景能不能分段設置在子View上,而不是圖方便直接設置在根View上。


4.ClipRect & QuickReject
為瞭解決Overdraw的問題,Android系統會通過避免繪製那些完全不可見的組件來儘量減少消耗。但是不幸的是,對於那些過於複雜的自定義的View(通常重寫了onDraw方法),Android系統無法檢測在onDraw裡面具體會執行什麼操作,系統無法監控並自動優化,也就無法避免Overdraw了。但是我們可以通過canvas.clipRect()來幫助系統識別那些可見的區域。這個方法可以指定一塊矩形區域,只有在這個區域內才會被繪製,其他的區域會被忽視。這個API可以很好的幫助那些有多組重疊組件的自定義View來控制顯示的區域。同時clipRect方法還可以幫助節約CPU與GPU資源,在clipRect區域之外的繪製指令都不會被執行,那些部分內容在矩形區域內的組件,仍然會得到繪製。除了clipRect方法之外,我們還可以使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形區域內的繪製操作。
clip方法詳解


5.使用ViewStub占位
ViewStub是個什麼東西?一句話總結:高效占位符。我們經常會遇到這樣的情況,運行時動態根據條件來決定顯示哪個View或佈局。常用的做法是把View都寫在上面,先把它們的可見性都設為View.GONE,然後在代碼中動態的更改它的可見性。這樣的做法的優點是邏輯簡單而且控制起來比較靈活。但是它的缺點就是,耗費資源。雖然把View的初始可見View.GONE但是在Inflate佈局的時候View仍然會被Inflate,也就是說仍然會創建對象,會被實例化,會被設置屬性。也就是說,會耗費記憶體等資源。推薦的做法是使用android.view.ViewStub,ViewStub是一個輕量級的View,它一個看不見的,不占佈局位置,占用資源非常小的控制項。可以為ViewStub指定一個佈局,在Inflate佈局的時候,只有ViewStub會被初始化,然後當ViewStub被設置為可見的時候,或是調用了ViewStub.inflate()的時候,ViewStub所向的佈局就會被Inflate和實例化,然後ViewStub的佈局屬性都會傳給它所指向的佈局。這樣,就可以使用ViewStub來方便的在運行時,要還是不要顯示某個佈局。

當你想載入佈局時,可以使用下麵其中一種方法:


6.用Merge減少佈局深度
Merge標簽有什麼用呢?簡單粗暴點回答:幹掉一個view層級。Merge的作用很明顯,但是也有一些使用條件的限制。有兩種情況下我們可以使用Merge標簽來做容器控制項。第一種子視圖不需要指定任何針對父視圖的佈局屬性,就是說父容器僅僅是個容器,子視圖只需要直接添加到父視圖上用於顯示就行。另外一種是假如需要在LinearLayout裡面嵌入一個佈局(或者視圖),而恰恰這個佈局(或者視圖)的根節點也是LinearLayout,這樣就多了一層沒有用的嵌套,無疑這樣只會拖慢程式速度。而這個時候如果我們使用merge根標簽就可以避免那樣的問題。另外Merge只能作為XML佈局的根標簽使用,當Inflate以<merge />開頭的佈局文件時,必須指定一個父ViewGroup,並且必須設定attachToRoot為true。
使用HierarchyViewer檢查佈局層級


7.善用draw9patch
給ImageView加一個邊框,你肯定遇到過這種需求,通常在ImageView後面設置一張背景圖,露出邊框便完美解決問題,此時這個ImageView,設置了兩層drawable,底下一層僅僅是為了作為圖片的邊框而已。但是兩層drawable的重疊區域去繪製了兩次,導致overdraw。優化方案: 將背景drawable製作成draw9patch,並且將和前景重疊的部分設置為透明。由於Android的2D渲染器會優化draw9patch中的透明區域,從而優化了這次overdraw。 但是背景圖片必須製作成draw9patch才行,因為Android 2D渲染器只對draw9patch有這個優化,否則,一張普通的Png,就算你把中間的部分設置成透明,也不會減少這次overdraw。


8.慎用Alpha
假如對一個View做Alpha轉化,需要先將View繪製出來,然後做Alpha轉化,最後將轉換後的效果繪製在界面上。通俗點說,做Alpha轉化就需要對當前View繪製兩遍,可想而知,繪製效率會大打折扣,耗時會翻倍,所以Alpha還是慎用。如果一定做Alpha轉化的話,可以採用緩存的方式。

通過setLayerType方式可以將當前界面緩存在GPU中,這樣不需要每次繪製原始界面,但是GPU記憶體是相當寶貴的,所以用完要馬上釋放掉。


9.避免“OverDesign”
overdraw會給APP帶來不好的體驗,overdraw產生的原因無外乎:複雜的Layout層級,重疊的View,重疊的背景這幾種。開發人員無節制的View堆砌,究其根本無非是產品無節制的需求設計。有道是“由儉入奢易,由奢入儉難",很多APP披著過度設計的華麗外衣,卻忘了簡單易用才是王道的本質,紛繁複雜的設計並不會給用戶帶來好的體驗,反而會讓用戶有壓迫感,產品本身也有可能因此變得卡頓。當然,一切拋開業務談優化都是空中樓閣,這就需要產品設計也要有一個權衡,在複雜的業務邏輯與簡單易用的界面展現中做一個平衡,而不是一味的OverDesign。



作者:Rave_Tian
鏈接:https://www.jianshu.com/p/2cc6d5842986
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 歡迎您的閱讀,本人微信公眾號 "星際互聯網中心"或者 "歡樂的馬小紀" 歡迎關註 ...
  • 1.瀏覽器無法直接通過url訪問 可能原因 :主機名未配置,因此無法識別,在 c:\windows\system32\drivers\etc 目錄添加主機名賀對應ip hostname1 *.*.*.8 2.訪問需要很長時間 hadoop配置文件,jobhistory緩存任務數太多,導致訪問緩慢 在 ...
  • 前言 儘管在Hadoop與NoSQL部署方面做足了準備,同樣的問題仍然一次又一次反覆出現。現在業界是時候儘快搞定這些麻煩事了。 有時候一艘巨輪的側方出現了破洞,但業界卻決定坐等船體下沉、並把希望寄托在銷售救生艇身上。 也有些時候,這些問題似乎並沒到要鬧出人命的地步——類似我家裡浴室的狀況,只有往一邊 ...
  • 經常有初學者在博客和QQ問我,自己想往大數據方向發展,該學哪些技術,學習路線是什麼樣的,覺得大數據很火,就業很好,薪資很高。如果自己很迷茫,為了這些原因想往大數據方向發展,也可以,那麼我就想問一下,你的專業是什麼,對於電腦/軟體,你的興趣是什麼?是電腦專業,對操作系統、硬體、網路、伺服器感興趣? ...
  • 一.概述 在前幾章介紹過 sql server 性能調優資源等待之PAGEIOLATCH,PAGEIOLATCH是出現在sql server要和磁碟作交互的時候,所以加個IO兩個字。這次來介紹PAGELATCH。PAGELATCH類型是sqlserver在緩衝池裡的數據頁面上經常加的另一類latch ...
  • 怎麼盜別人的微信號密碼最簡單方法與軟體及如何盜取對方的微信密碼? 微信可以說是十分重要的一個社交軟體,隨著用戶數量日益增多,人們在生活和中工作中往往離不開微信。但是關於微信的一些話題曾出不窮,甚至讓人防不勝防。因為稍不留神微信號便會被盜,所以只要是使用微信的朋友,在收到僵屍粉的同時,一定要儘快將其清 ...
  • 揭曉黑客步驟:盜微信號密碼最簡單方法與軟體以及怎麼盜取微信密碼? 隨著信息時代的來臨,很多人使用上了微信,微信的出現使得人們的生活變的十便利。人們不僅在工作中使用它,在社交中也讓其發揮了重要的作用。微信現在已經漸漸成為了人們生活中不能缺少的一部分。使用微信除了其方便快捷性之外,其賬號的安全性也引發了 ...
  • Android性能優化學習 最近公司主抓性能優化工作,藉此春風也學習到了許多Android性能優化方面的知識。由於組內隊友的給力,優化的成果也是比較喜人。同時也學習和實踐了不少知識,特此記錄。 1.性能優化分析工具學習 在開始代碼優化之前,先得學會使用性能分析工具。以下三個工具都是谷歌官方推出的,可 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...