編輯:關於Android編程
布局優化 內存優化 使用各種工具進行分析,優化隨著Android應用增多,功能越來越復雜,布局也越來越豐富了,而這些也成為了阻礙一個應用流暢運行,因此,對復雜的功能進行性能優化是創造高質量應用的基礎,本章節將為大家展示幾種性能優化的方法,幫助開發者快速的構建運行速度快,相應速度快的應用程序
系統在渲染圖片的時候需要消耗大量的資源,一個好的UI,不僅要有良好的視覺體驗,更應該具有良好的使用體驗,因此布局優化就顯得很重要了
人眼所看到的流暢畫面,需要畫面的幀數達到40幀每秒到60幀每秒,相信玩過PC游戲的都應該對幀有一個詳細的概念,最佳的ftp在60左右,這也是評價一個顯卡性能的一個高低標准之一,在Android中,系統通過VSYNC信號出發對UI的渲染、重繪,其間隔時間是16ms。這個16ms其實就是1000ms中顯示60幀畫面的單位時間。即1000、60,如果系統每次渲染都保持在16ms之內,那麼我們看到的UI將十分的流暢,但這也是需要將所有的邏輯都保證在16ms裡,如果16ms不能完成繪制,那麼就會造成丟幀的現象,即當前該重繪的幀被未完成的邏輯阻塞
Android系統提供了檢測UI渲染時間的工具,打開“開發者選項”,選擇“Profile GPU Rendering”(我的手機是“GPU呈現模式分析”),選中“On screen as bars”(我的為“在屏幕上顯示為條形圖”)。每一條柱狀線都包括三部分,藍色代表測量繪制Display List的時間,紅色代表OpenGL渲染Display List所需要的時間,黃色代表CPU等待GPU處理的時間,中間綠色橫線代表VSYNC時間16ms,需要盡量將所有條形圖都控制在這條綠線之下。
Overdraw,過渡繪制會浪費很多CPU、GPU資源,例如系統默認會繪制Activity的背景,而如果再給布局繪制了重疊的背景,那麼默認Activity的背景就屬於無效的過渡繪制。Android系統在開發者選項中提供了這樣一個檢測工具–“Enable GPU Overdraw”。借助它可以判斷Overdraw的次數。盡量增大藍色的區域,減少紅色的區域,這裡,我們用一張Google開發者博客上的圖片來表示
通過這個工具可以查看當前區域中繪制的次數,從而盡量優化繪圖層次,盡量增大藍色的區域,減少紅色的區域<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxoMyBpZD0="3優化布局層級">3.優化布局層級
在Android中系統對View的測量、布局和繪制都是通過遍歷View樹來進行的,如果View樹太高,就會影響其速度,因此優化布局的第一個方法就是減低view樹的高度,Google也在其api文檔中建議view樹的結構不宜超過十層
不知道是否讀者有注意到,在早期的Android版本中,Google使用線性布局作為默認布局,而在現在的Android使用的是相對布局(默認),原因就是通過扁平的相對布局來降低通過線性布局所產生的樹的高度,從而提高布局的效率
4.避免嵌套過多無用的布局
嵌套的布局會讓view樹的高度越來越高,所以在布局中,需要根據自身布局的特點,來選擇不同的layout組件,從而避免通過某一種layout組件來實現功能時的局限性,從而造成嵌套過多的形象‘
-1.使用< include>標簽重用布局
在一個應用程序裡,為了風格和是哪個的統一,很多界面都會存在一些共同的UI,比如toolbar什麼的,我們就可以使用< include>標簽重用布局
下面我們來演示一下如何使用< include>標簽,為了能夠在不同的layout,所以再好不要寫太多只有一個layout屬性的組件,這裡我們看一個非常簡單的布局
代碼中只有一個textview,並且顯示一段文字,但是更多的時候,我們會通過相應的layout去簡化,那麼我們是如何去使用共同的ui尼,只需要使用該共通UI的布局文件中使用標簽就可以了
這樣,當我們運行的時候就可以知道看到已經把布局插進去了
-2.使用< ViewStud>實現view的延遲加載
除了把一個view作為公用的ui,還可以對他進行延時加載,用< ViewStud>就可以輕松實現,< ViewStud>是一個輕量級的組件,他不僅不可視,而且大小為0,我們用小案例說話
我們先寫一個布局
然後我們使用< ViewStud>這個標簽
運行之後,我們發現引用的組件確實沒有加載出來,那要怎麼去加載尼?,同樣的,我們需要找控件
ViewStub viewStub = (ViewStub) findViewById(R.id.viewStub);
這裡,提供了兩種方式來重新顯示這個view
VISIBLE通過調用ViewStub的setVisibility()方法來顯示這個view
inflateviewStub.setVisibility(View.VISIBLE);
通過調用ViewStub的inflate方法來顯示這個view
View inflateView = viewStub.inflate();
這兩種方式都可以讓ViewStub重新展開,顯示引用的布局,而唯一的區別就是inlalte方法可以返回引用的布局
這裡可能有同學有疑問了, ViewStub標簽和設置View.GONE有什麼區別,的確,他們兩個剛開始都不會加載,但是ViewStub只會顯示的時候,才去渲染這個布局,而後者不是,這就是優勢
5.Hierarchy Viewer
無論哪本將優化的書,他們都不得不提到5.Hierarchy Viewer,不過通常情況下,5.Hierarchy Viewer無法再真機上進行使用,他只能在工場的Demo機上測試即非加密過的設備,Google大神-Romain Guy提供了一個開源的View service,通過這個程序,也能讓普通的手機使用5.Hierarchy Viewer,,我們就是來使用一下吧啊,進入sdk目錄下的/tools/啟動hierarchyviewer
選擇要調試的進程,然後點擊上面的load view Hierarchy按鈕
為了測試這個工具,我們寫一段非常爛的代碼
然後我們來看看
我們使用多層的線性布局,這個代碼是多余的,通常情況下,我們關心ID為content的分支,這是setvontenview所設置的內容
這裡我們就可以看到我們的線性布局
當點擊一個view的時候,可以顯示改view的繪制情況,不過第一次顯示的時候,各種顯示時間都是NA,需要點擊菜單中的“profile node”重新計算
此時就可以知道每個view所繪制的時長,並且在系統的下方給出三個不同顏色的小圓點,用來表示繪制的效率,綠黃紅,好,中,差
通過Hierarchy工具就可以很快的找到視圖樹上多余的布局了,從而有目的去優化布局了,
二.內存優化
應用App內存的使用,也是評價一個應用性能高低的一個重要指標。雖然現在智能手機的內存越來越大,但是一個好的應用應當將效率發揮到極致,精益求精。而現在有很多應用, 為了自己的利益,使用一些非常影響系統效率的方法, 不僅敗壞了Androld的口碑, 更極大地影響了系統的穩定性,例如某 “X米”團購應用,在啟動應用的時候會fork一個子線程, 用於監聽用戶卸載應用。在KK下, 該線程在卸載時不能被kill,且每次啟
動都將fork新的進程;這就導致內存消耗不斷增高, 極大地影響了低端機的使用體驗,因此,不管是什麼應用,都應該把內存效率,用戶體驗放在首位,而不是為了滿足自己的利益
1.什麼是內存
由於Android的沙箱機制,每個應用所分配的內存大小是有限度的,內存太低就會觸發LMK-Low Memory Killer機制。那麼到底什麼是內存呢?通常情況下我們所說的內存是指手機的RAM,它包括以下幾個部分
寄存器(Registers)
速度最快的存儲場所,因為寄存器位於處理器內部.在程序中無法控制
棧(Stack)
存放基本類型的數據和對象的引用.但對像本身不存放在棧中,而是存放在堆中
堆內存(Heap)
堆內存用來存放由new創建的對象和數組.在堆中分配的內存,由java虛擬機的自動垃圾回收(GC)管理
靜態存儲區域(static Field)
靜態存儲區域就是指在固定的位置存放應用程,子運行時一直存在的數據,java在內存中專門劃分了一個靜態存儲區域來管理一些特殊的 數據變量如靜態的數據變量
常量池(Constant Pool)
JVM虛擬機必須為每個被裝載的類型維護一個常量池,常量池就是該類型所用到常量的一個有序集合,包括直接常量(基本類型,String)和對其他類型. 字段和方法的符號引用
在這些概念中最容易搞錯的就是堆和棧的區分。當定義一個變量,Java虛擬機就會在棧中為該變量分配內存空間 這部分內存空間會馬上被用作新的空間進行分配,如果使用new的方式創建一個變量, 那麼就會在堆中為這個對象分配內存空間,即使該時象的作用域結束, 這部分內存也不會立即被回收.而是等待系統Gc進行回收,堆的大小隨著手機的不斷發展而不斷變大,在過程中.可以使用如下所示的代碼來獲得堆的大小,所謂的
內存分析,正是分析Heap中的內存狀態。
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); int heapSize = manager.getLargeMemoryClass();
2.獲取Android系統內存信息
-1.Process Stats
Process Stats是KK上新增的一個系統內存監視服務. 可以通過’Setting-Developer options-Process Stats來開啟該功能
同樣也可以使用Dumpsys命令來獲取這些信息
agb shell dumpsys procstats
-2.Meminfo
Meminof也是系統的一個非常重要的內存監視工具,可以通過setting-apps-running打開,如圖
同樣,我們也可以通過adb命令來實現
agb shell dumpsys meminfo
-3.內存回收
java對於C/C+這類語言最大的優勢就是不用手動管理系統資源,java創建了垃圾收集器線程來自動進行資源的管理 這樣做的好處是大大降低了程序開發人員對內存管理的繁瑣工作,但這也帶來了很多問題,例如java的gc是系統自動進行的,但何時進行卻是開發者無法控制的,即使調用system.gc方法,也只是建議系統進行GC,但是系統是否采納你的建設.那就不一定了。JVM虛擬機雖然能夠自動控制GC,但是再強大的算法,也難免會存在部分對象忘記回收的現象發生, 這就是造成內存洩漏的原因
-4.內存優化實例
下面來看兩個內存優化的實例 分別從Binnap和代碼兩個角度來對內存進行優化。
Bitmap 優化
Bitmap是造成內存占用過高甚至是OOM的最大威脅,下面給出一些使用Bitmap的技巧
使用適當分辨率和大小的圖片
由於Android系統在做資源適配的時候會對不同分辨率文件夾下的圖片進行縮放來適配相應分辨率.如果圖片分辨率與資源文件分辨率不匹配或若圖片分辨率太高,就會導致系統消耗更多的內存資源.同時,在適當的時候,應該顯示合適大小的圖片,例如在圖片列表界面可以使用的縮略圖thumbnails,而在現實詳細圖片的時候在顯示原圖,或者在對圖片要求不高的地方盡量降低圖片的精度.
及時回收內存
一旦用完Bitmap後,一定要及時使用bitmap.recycle()方法來釋放資源,自Android3.0後,由於bitmap被放置到了堆內存由gc管理.就不需要釋放了
使用圖片緩存
通過內存緩存(LrcCache)和硬盤緩存(DiskLrcCache) 可以更高的使用bitmap
代碼優化
任何Java類,都將占用大約500字節的內存空間,創建一個類的實例會消耗大約15子節的內存。從代碼的實現方式上,也可以對內存進行優化 這裡同樣總結了一些小的技巧
對常量使用static修飾符 使用靜態方法,靜態方法會比普通方法提高15%左右的訪問速度 減少不必要的成員變量 ,這點在Android Lint工具上已經集成檢測了.如果一個變量可以定義為局部變量,則會建議你不要定義為成成變量. 減少不必要的對象 使用基礎類型會比使用對象更加節省資源, 同時更應該避免頻繁創建短作用域的變量 盡量不要使枚舉、少使用迭代器。 對Cursor,Receiver,Sensor,Fiie等對象,要非常注意對它們的創建.回收與注冊解注冊。 避免使用IOC框架.IOC通常使用注解.反射來進行實現,雖然現在java對反射的效率已經進行了很好的優化.但大量使用反射依然會帶來性能的下降. 使用RenderScript,openGL來進行非常復雜的繪圖操作. 使用surfaceView來替View進行大量.頻繁的繪圖操作. 盡量使用視圖緩存,而不是每次都執行inflaler()方法解析視圖三.Lint工具
Android Lint工具是Android studio中繼承的一個代碼提示工具,他可以給你的布局,代碼提供非常強大的幫助,比如在前面的例子,如果在布局文件中,寫了三個對於的布局,那麼他是這樣提示的
當然,這只是一個很簡單的例子,Lint的功能非常的強大,大家應該養成寫完代碼之後檢查lint的習慣,這不僅可以讓我們及時的發現一些隱藏的問題,而且,更讓我們養成良好的代碼風格,要知道,這些Lint提示可都是Google工程師的汗水和智慧的結晶
四.使用Android Studio的Memory Monitor工具
Memory Monitor工具是Android studio上的一個內存監視工具,他可以很好的幫助我們進行內存實時分析,通過點擊Android studio右下角的Memory Monitor標簽就可以進行查看了
五.使用TraceView工具優化APP性能
TraceView是一個Android下的可視化性能調查工具,它用來分析TraceView的日志
1.生成TraceView日志的兩種方法
生成TraceView日志的兩種方法,一種是利用debug類幫助我們生成日志文件,另一種方法就是利用Android device monitor工具輔助生成文件
-1.通過代碼生成精確范圍的TraceView日志
使天debug類的方法開啟TraceView監聽,通過調用Debug.startMethodTracing()方法開啟監聽。 通過調用 Debug.stopMethodTracing()來停止監聽;我們可以使用這兩個方法
來包圍要監聽的代碼塊,例如在oncreate方法裡調用開啟,在ondesty()方法來結束,TraceView的日志將會保存到 /sdcard/ dmtrace.trace 目錄下,因此, 需要在清單文件中增加如下
所示的權限
當然, 除了使用默認的輸出日志名,也可以自定義路徑和日志名
當要監聽的內容執行完畢後,通過ADB命令將日志文件導出到本地,
命令如下所示
adb pull /adcard/trace_log/local/LOG/
-2 通過Android Device Monltor生成TiaceView日志
打開Android studio的Android device monitor工具,選擇要調試的進程,,點擊工具欄中start method profi1ing’按鈕,點擊後會彈出提示, 選擇監聽的模式,TiaceView提供了以下兩種監聽方式。
整體監聽跟蹤每個方法執行的全部過程,這種方式資源消耗較大
抽樣監聽按照指定的平率進行抽樣調查,這種方式需要較長的時間來獲取較為精准的樣本數據,執行一段時間之後,再次點擊按鈕則會取消監聽
2.打開TiaceView日志
對於導出的TiaceView日志文件,可以使用SDK的sdk\tools\traceview.bat工具來打開或者在ADM工具中,選擇File,open file,
3.分析TiaceView日志
TiaceView的分析界面共有兩部分,上面是用於顯示方法的時間和時間軸區域,下面是profile區域
-1.時間軸區域
時間軸區域顯示了不同線程在不同的時間段的執行情況,在時間軸中,每一行都代表了一個獨立的線程
-2.Profile區域
Profile區域顯示了你選擇的色塊所代表的方法和該色塊所處的時間段的性能分析
Profile區域主要顯示一下的一些信息
Incl CPU Time - 某方法占用CPU的時間 Excl CPU Time - 某方法本身占用的CPU Incl Real Time - 某方法真正執行的時間 Call+RecurCalls - 調用次數+遞歸回調的次數每個時間都包含兩列,一個是實際的時間,另一個是百分比,分析的時候,通常從Incl CPUTime和Call+RecurCalls開始進行分析,對占用時間長的方法進行重點分析,如果占用時間長且Call+RecurCalls次數少, 那麼就可以列為懷疑對象了
六.使用MAT工具分析APP內存狀態
MAT工具是一個分析內存的強力助手
1.生成HPROF文件
首先打開Android Device Monitor工具,選擇要監聽的線程,並且點擊菜單的uPDATE HPROF按鈕,
在HEAP標簽中,點擊Cause GC
就會顯示當前的內存狀態,
這裡有一 個判斷當前是否存在內存洩漏的小技巧,當我們不停地點擊Cause GC按鈕的時候,如果data object中的“Total size 有明顯變化,就代表可能存在內存洩漏
上面是手動查看Heap狀態, 下面點擊菜單欄的’Dump HPRoF Filc按鈕, 如圖
竽待幾秒鐘後,系統就會生成一個hprof文件,我們要分析的就是這個文件。將它保存到PC上,默認名為包名.hprof不過對這個文件我們還不能直接使用MAT工具進行分析,需要進行格式轉換。在命令行下,切換到SDK目錄的platfrom一tools目錄下,使用hproicoow工具
hprof-conv
執行
命名格式為”hprof-conf infile outfile”,使用生成的heap.hprof文件可以利用MAT工具進行分析了
2.分析HPROF文件
打開MAT工具,選擇open a heap Dump選項,等待文件導入
後面還可以進行更深人的分析,MAT功能強大,這裡主要看以下幾個功能
- Histogram
Histograrn直方圖,用於顯示內存中每個對象的數量,大小和名稱。點擊後打開Histogram標簽
在最上方一行,可以通過搜索過濾相應的關鍵字,這點在分析內存中是非常有用的,比如可以過濾game關鍵字
在選擇的對象上單擊鼠標右鍵,在跳出的快捷菜單中選擇list objects-witch incoming references 選項查看具體的對象
Dominator Tree
Dominator Tree支配樹會將內存中的對象按照帶下進行排序的,並且顯示對象之間的引用結構,點擊打開Dominator Thee標簽,對象已經按照Retained Heap進行排序了,即按照對象及所持有的引用內存總和進行排序,通過分析內存占用找到內存消耗的原因
七.使用Dumpsys命令分析系統狀態
使用Dumpsys命令可以列出Android系統相關的信息和服務狀態,Dumpsys命令的功能非常強大,可使用的參數配置也非常多
Dumpsys所支持的命令非常多,這裡就不列舉了
使用Dumpsys命令時.只需要輸人“adb Shell dumpsys + 參數就可以,我們來獲取一下acticity棧的信息
adb shell dumpsys activity
下面的列表中,總結了一些常用的Dumpsys參數
Linux下的shell命令,如grep、“find’等,可以讓Dumpsys命令發揮非常強大的作用,這進行性能優化.Bug分析時是非常有的.
性能優化是一個非常具有挑戰性的工作,上面列舉了很多分析內存丶優化內存的方法.但真正的優化工作遠不止這麼簡單.這裡只是列舉了一些人門的方法,而要進行完美的內存優化內存分析絕非一 日之功,需要開發者有深厚的技術功底和耐心.
通過View提供的方法獲取高度方式有兩種:1, 當前顯示的view中直接獲取當前view高寬2, 通過Activity的getWindow().findViewById(
承香墨影Android--ColorMatrix改變圖片顏色 前言 本篇博客講解如何通過改變圖片像素點RGB的值的方式,在Android中改變圖片
使用SlidingTabLayout需要准備2個類,分別是 SlidingTabLayout,與SlidingTabStrip,,放進項目中時只用修改下包名即可。效果制作
目前正在做的一個小項目中遇到了需要制作弧形listview的需求,要求是listview向右變為弧形,在空白部分顯示一定的內容。具體顯示如下: 以屏幕左上角或者