因?yàn)楸娝苤脑?Android APP總是需要調(diào)優(yōu),今天筆者就介紹一下Google工程師提供給我們的優(yōu)化工具以及如何使用他們查找解決性能問題的方法镀娶。
一般來說,APP主要的就是往以下四個(gè)方面優(yōu)化,各種調(diào)優(yōu),優(yōu)化,都是奔著這四個(gè)方面去等浊。
1 ANDROID優(yōu)化工具的使用
1.1 Profile
Android Stduio3.1之后就取消了DeviceMonitor,開始全面使用Profile,而Profile又細(xì)分了三個(gè)方面,慢慢來介紹
1.1.1 CPU Profile 讓你的APP更快
AS為我們自動創(chuàng)建了兩個(gè)CPU Profile的默認(rèn)配置,一個(gè)是Sample Java Method,另一個(gè)是Trace Java Method,而這兩者之間有什么區(qū)別呢樟遣?
最主要的區(qū)別就是:Sample 會頻繁的捕捉調(diào)用堆棧以獲取具體信息。而Trace則是在每個(gè)函數(shù)開始之前跟結(jié)束之后記錄時(shí)間戳,然后分析數(shù)據(jù)已烤。
舉個(gè)例子,
fun add(int a ,int b):int = a+b
函數(shù)A僅僅執(zhí)行一個(gè)加法運(yùn)行,運(yùn)行時(shí)間非常短暫,那么如果Sample恰好在進(jìn)入此函數(shù)之前捕捉了一次堆棧信息且在此函數(shù)退出后,又捕捉了一次堆棧信息,那么A函數(shù)則不會被分析器記錄锐峭。而Trace則不同,Trace是在每個(gè)函數(shù)開始之前與結(jié)束之后記錄時(shí)間戳,所以不會錯(cuò)失任何一次函數(shù)調(diào)用,但是Trace的問題就在于,頻繁記錄很可能會超出記錄文件限定的大小(默認(rèn)為8M)
所以如何取舍,還是要看自己。
1 選擇時(shí)間范圍: 用于確定您要在跟蹤窗格中檢查所記錄時(shí)間范圍的哪一部分驾讲。 首次記錄函數(shù)跟蹤時(shí)蚊伞,CPU Profiler 將在 CPU 時(shí)間線中自動選擇記錄的完整長度。如果只想記一小部分,則可以使用自主選擇
2 時(shí)間戳: 用于表示所記錄函數(shù)跟蹤的開始和結(jié)束時(shí)間(相對于分析器從設(shè)備開始收集 CPU 使用率信息的時(shí)間)吮铭。 在選擇時(shí)間范圍時(shí)时迫,您可以點(diǎn)擊時(shí)間戳以自動選擇完整記錄,如果您有多個(gè)要進(jìn)行切換的記錄谓晌,則此做法尤其有用掠拳。
3 跟蹤窗格: 用于顯示您所選的時(shí)間范圍和線程的函數(shù)跟蹤數(shù)據(jù)。 僅在您至少記錄一個(gè)函數(shù)跟蹤后此窗格才會顯示纸肉。 在此窗格中溺欧,您可以選擇想如何查看每個(gè)堆疊追蹤(使用跟蹤標(biāo)簽),以及如何測量執(zhí)行時(shí)間(使用時(shí)間引用下拉菜單)柏肪。
4 選擇后姐刁,可通過 Top Down 樹、Bottom Up 樹烦味、調(diào)用圖表或火焰圖的形式顯示您的函數(shù)跟蹤聂使。 您可以在下文中了解每個(gè)跟蹤窗格標(biāo)簽的更多信息。
從下拉菜單中選擇以下選項(xiàng)之一,以確定如何測量每個(gè)函數(shù)調(diào)用的時(shí)間信息:
5 Wall clock time:壁鐘時(shí)間信息表示實(shí)際經(jīng)過的時(shí)間柏靶。
6 Thread time:線程時(shí)間信息表示實(shí)際經(jīng)過的時(shí)間減去線程沒有消耗 CPU 資源的任意時(shí)間部分弃理。 對于任何給定函數(shù),其線程時(shí)間始終少于或等于其壁鐘時(shí)間宿礁。 使用線程時(shí)間可以線程的實(shí)際 CPU 使用率中有多少是給定函數(shù)消耗的案铺。
其又分四個(gè)具體標(biāo)簽,分別是Call Chart,Flame Chart,Top Down,Bottom Up
Call Chart跟Flame Chart都是圖標(biāo)形式的體現(xiàn),一個(gè)是順序調(diào)用,一個(gè)是逆序
Top Down,Bottom Up也與其類似,不過都是函數(shù)具體調(diào)用,一個(gè)是從上至下,一個(gè)是自低向上
最簡單區(qū)分方法就是:TopDown 與 Call Chart都是從main函數(shù)開始蔬芥,往下記錄被調(diào)用函數(shù),而Flame Chart跟Bottom Up則是從底層函數(shù)開始回溯梆靖。
總結(jié):CPU Profile可幫助我們分析程序具體哪個(gè)函數(shù)耗時(shí)最多,最影響性能,右鍵跳轉(zhuǎn)源碼,可直接定位到具體代碼。
1.1.2 Memory Profile 讓你的APP更穩(wěn)
性能優(yōu)化的重中之中,內(nèi)存分析器,自從有了APP顯示Bitmap, OOM就是最讓人蛋疼的異常錯(cuò)誤,因?yàn)椴粌H要修改大小,還要優(yōu)化代碼,壓縮bitmap笔诵。
而如今,我們可以借助Memory Profile來分析返吻。大名鼎鼎的leakCanary也是根據(jù)hprof文件來對比分析定位是否有內(nèi)存泄漏。
內(nèi)存計(jì)數(shù)中的類別如下所示:
- Java:從 Java 或 Kotlin 代碼分配的對象內(nèi)存乎婿。(這個(gè)對象就是我們主要關(guān)注的,代碼申請的對象總大小)
- Native:從 C 或 C++ 代碼分配的對象內(nèi)存测僵。Framwork層的對象
- Graphics:圖形緩沖區(qū)隊(duì)列向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內(nèi)存谢翎。 (android系統(tǒng)16ms發(fā)送一次Vsync信號,通知GPU渲染數(shù)據(jù),這份是GPU專用用來存儲未渲染的數(shù)據(jù)隊(duì)列)
- Stack:應(yīng)用中的原生堆棧和 Java 堆棧使用的內(nèi)存捍靠。 這通常與應(yīng)用運(yùn)行多少線程有關(guān)。(申請的堆棧內(nèi)存)
- Code:應(yīng)用用于處理代碼和資源(如 dex 字節(jié)碼森逮、已優(yōu)化或已編譯的 dex 碼榨婆、.so 庫和字體)的內(nèi)存。
- Other:應(yīng)用使用的系統(tǒng)不確定如何分類的內(nèi)存褒侧。
-
Allocated:應(yīng)用分配的 Java/Kotlin 對象數(shù)良风。 它沒有計(jì)入 C 或 C++ 中分配的對象。
heapDump
將堆轉(zhuǎn)儲另存為 HPROF
用來查看具體分配的對象以及占據(jù)的內(nèi)存大小,不過heapDump文件不是永久的,如果想要保存下來還使用 Export heap dump as HPROF file!
闷供,將堆轉(zhuǎn)儲導(dǎo)出到一個(gè) HPROF 文件中烟央。下次再打開就可以直接使用了。
檢測內(nèi)存泄漏
以前有Device Monitor咱們是先存儲一次hprof文件,然后頻繁操作再頻繁gc,再來保存一次hprof文件,然后用Mat工具對比查看兩個(gè)文件是否有大的區(qū)別,而如今Google又介紹了一個(gè)簡單的,查看是否有內(nèi)存泄漏的方法:
- 將設(shè)備從縱向旋轉(zhuǎn)為橫向歪脏,然后在不同的 Activity 狀態(tài)下反復(fù)操作多次疑俭。 旋轉(zhuǎn)設(shè)備經(jīng)常會導(dǎo)致應(yīng)用泄漏 Activity,Context或 View 對象,因?yàn)橄到y(tǒng)會重新創(chuàng)建 Activity婿失,而如果您的應(yīng)用在其他地方保持對這些對象之一的引用怠硼,系統(tǒng)將無法對其進(jìn)行垃圾回收。
- 處于不同的 Activity 狀態(tài)時(shí)移怯,在您的應(yīng)用與另一個(gè)應(yīng)用之間切換(導(dǎo)航到主屏幕香璃,然后返回到您的應(yīng)用)
1.1.3 NetWork Profile
分析應(yīng)用網(wǎng)絡(luò)使用情況,由于現(xiàn)在一般不太在乎網(wǎng)絡(luò)的使用情況,畢竟5G時(shí)代馬上來臨,所以這部分暫時(shí)擱置,各位同學(xué)有興趣的可以自己研究如何使用。
1.2 Lint
Analyzer->Inspect Code 即可啟用Lint
1.2.1 輔助功能 Accessibility
重要指數(shù):一般
一般指的是控件該有的標(biāo)簽沒有,比如ImageView的android:contentDescription 屬性,這個(gè)標(biāo)簽主要是給盲人用的,Google Assistant會根據(jù)這個(gè)屬性的值來幫助盲人理解舟误。如果有興趣的同學(xué)可以自己繼續(xù)研究葡秒。
1.2.2 健壯性 Correctness 讓你的APP更穩(wěn)
重要指數(shù):重要
一般會提示四大組件 比如Activity跟Service等沒有注冊,影響APK被PKMS解析
代碼使用方面的問題,如果使用了Private API則會提示將來不支持,會引起異常崩潰,想必大家都體驗(yàn)過在XX機(jī)型上莫名其妙的Crash問題,所以這個(gè)標(biāo)簽下的內(nèi)容大家一定要注意檢查,務(wù)必使其消失。
1.2.3 國際化 Internationalzation
重要指數(shù):一般
顧名思義,這個(gè)是為了以后國際化使用的眯牧,例如項(xiàng)目內(nèi)如果寫了settext("hello"),則會提示此警告,如果不用國際化,則不須考慮此提示,否則必須使用Res string.xml 進(jìn)行plachholder
1.2.4 表現(xiàn)力 Performance
重要指數(shù):極其重要
OverDraw:Painting regions more than once
眾所周知,Android APP里面最重要的優(yōu)化方面之一就是UI繪制方面優(yōu)化,避免嵌套層級過多,導(dǎo)致多次onDraw,浪費(fèi)性能從而造成APP卡頓
Lint此條目即可幫我們掃描到哪些XML有OverDraw的可能性蹋岩。
開發(fā)的同學(xué)務(wù)必注意此條,按照提示的內(nèi)容逐一檢查,必須使Overdraw提示消失。
Unused resource
檢測無用資源,減小apk體積,便于渠道商推廣
1.2.5 安全性 Security
重要指數(shù):一般
主要是提示高版本SDK下,app的兼容性可能會出問題
1.2.6 可用性 Usability
重要指數(shù):一般
主要是提示能不能被Google搜索到,跟一些統(tǒng)計(jì)用量,如果專注于國內(nèi)開發(fā)可不用考慮這個(gè)
1.2.7 資源可用性 Android Resource Validation
重要指數(shù):一般
主要檢測XML文件是不是引用了無效資源,當(dāng)然 一般如果不修改好 編譯過不去,大家也會修改的学少。
個(gè)人建議如果時(shí)間比較趕,來不及做很多優(yōu)化,其他暫時(shí)都可以放放,直接把Performance里面的建議執(zhí)行完即可剪个。Lint的局限性在于其只能檢測是否Overdraw,而類似數(shù)據(jù)大量加載導(dǎo)致的卡頓則需各位同學(xué)自己注意,利用CPU Profile去檢測。
另外此處是Google給出的減少過度繪制的方法 :
There are several strategies you can pursue to reduce or eliminate overdraw:
- Removing unneeded backgrounds in layouts.(移除不需要的背景)
- Flattening the view hierarchy.(布局扁平化,即少嵌套,多用LinearLayout版确,ConstraintLayout)
- Reducing transparency.(減少透明,替換Windows自帶背景,不要在Theme文件里設(shè)置WindowTransparent)
檢測是否真的減少繪制:
啟用開發(fā)者選項(xiàng), 然后扣囊,執(zhí)行以下操作:
- Settings 并點(diǎn)按 Developer Options。
- 向下滾動到 Hardware accelerated rendering 部分绒疗,并選擇 Debug GPU Overdraw侵歇。
- 在 Debug GPU overdraw 對話框中,選擇 Show overdraw areas吓蘑。
Android 按如下方法為界面元素設(shè)置顏色惕虑,以便確定過度繪制的次數(shù):
真彩色(也就是原色): 沒有過度繪制
-
藍(lán)色
藍(lán)色: 過度繪制 1 次
-
綠色
綠色: 過度繪制 2 次
- 粉色
粉色: 過度繪制 3 次
-
紅色
紅色: 過度繪制 4 次或更多
InspectCode的結(jié)果還有其他很多種,因此篇主要講Android的優(yōu)化,其他的結(jié)果是項(xiàng)目代碼方面的問題就不研究了,有興趣的讀者可以自己深入研究。
1.3 LayoutInspector 布局檢查器
LayoutInspector 是另外一個(gè)檢測布局的便利工具,可以檢測出布局是否有嵌套,使用方式如下:
- 連接手機(jī),運(yùn)行程序
- 點(diǎn)擊Tools->LayoutInspector->show all process
-
choose your app
這樣,LayoutInspector就連接上手機(jī)APP了磨镶,然后開始進(jìn)行布局分析,選擇一個(gè)對應(yīng)的APP,就可以看到具體的信息,LayouInspector會自動將它保存為 .li 文件并打開溃蔫。 如圖中所示,布局檢查器將顯示以下內(nèi)容:
View Tree:視圖在布局中的層次結(jié)構(gòu)琳猫。
Screenshot:帶每個(gè)視圖可視邊界的設(shè)備屏幕截圖伟叛。
Properties Table:選定視圖的布局屬性。
捕捉的快照
如果布局包括重疊視圖沸移,則默認(rèn)情況下痪伦,只有前面的視圖可以在屏幕截圖中點(diǎn)擊。 要讓后面的視圖可以在屏幕截圖中點(diǎn)擊雹锣,請執(zhí)行以下操作: 在 View Tree 中右鍵點(diǎn)擊前面的視圖网沾,然后取消選中 Show in preview。 此操作不會讓視圖內(nèi)容消失蕊爵;僅會讓屏幕截圖中的可點(diǎn)擊邊界消失辉哥,以便您可以點(diǎn)擊在它后面的視圖。
所有LayoutInspector捕捉的.li文件 都會保存在/project/captures/ 內(nèi)一個(gè)單獨(dú)的 .li 文件中攒射。
這個(gè)工具主要是便于直接查看app的實(shí)際布局是否過度嵌套醋旦。
1.4 ProGuard - 壓縮代碼以及資源 讓你的APP更小
ProGuard 眾所周知 是開啟混淆的利器,但是他還有另外一種作用,就是減輕APK的體積,去掉無用代碼,讓我們來看看Google官方對此的介紹
- 通過 ProGuard 移除未使用的代碼 - 為您的版本構(gòu)建[啟用代碼壓縮]以運(yùn)行 ProGuard。啟用壓縮可確保您交付的 APK 不含有未使用的代碼会放。代碼壓縮通過 ProGuard 提供泛粹,ProGuard 會檢測和移除封裝應(yīng)用中未使用的類键思、字段、方法和屬性,包括自帶代碼庫中的未使用項(xiàng)宗侦。ProGuard 還可優(yōu)化字節(jié)碼,移除未使用的代碼指令,以及用短名稱混淆其余的類、字段和方法酸纲。混淆過的代碼可令您的 APK 難以被逆向工程瑟匆,這在應(yīng)用使用等安全敏感性功能時(shí)特別有用闽坡。
資源壓縮 通過適用于 Gradle 的 Android 插件提供,該插件會移除封裝應(yīng)用中未使用的資源愁溜,包括代碼庫中未使用的資源疾嗅。它可與代碼壓縮發(fā)揮協(xié)同效應(yīng),使得在移除未使用的代碼后祝谚,任何不再被引用的資源也能安全地移除宪迟。
本文介紹的功能依賴下列組件:- [SDK Tools] 25.0.10 或更高版本
- [適用于 Gradle 的 Android 插件]2.0.0 或更高版本
啟用代碼壓縮,直接在build.gradle文件內(nèi)相應(yīng)的構(gòu)建類型中添加 minifyEnabled true
每次構(gòu)建時(shí) ProGuard 都會輸出下列文件:
- dump.txt
說明 APK 中所有類文件的內(nèi)部結(jié)構(gòu)酣衷。- mapping.txt
提供原始與混淆過的類交惯、方法和字段名稱之間的轉(zhuǎn)換。- seeds.txt
列出未進(jìn)行混淆的類和成員穿仪。- usage.txt
列出從 APK 移除的代碼席爽。
這些文件保存在 <module-name>/build/outputs/mapping/release/ 中。
啟用資源壓縮啊片,在 build.gradle 文件中將 shrinkResources 屬性設(shè)置為 true
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
排查資源壓縮問題
Gradle 還會在 <module-name>/build/outputs/mapping/release/(ProGuard 輸出文件所在的文件夾)中創(chuàng)建一個(gè)名為 resources.txt 的診斷文件只锻。該文件包括諸如哪些資源引用了其他資源以及使用或移除了哪些資源等詳情。
GPU Rendering 渲染解析圖,可根據(jù)此圖分析判斷性能消耗在何處
總結(jié):本文主要介紹了Android性能優(yōu)化的工具紫谷,其重點(diǎn)在于讓APP
更穩(wěn): Memory Profile 檢測內(nèi)存泄漏問題,內(nèi)存優(yōu)化問題
更快:CPU Profile 檢測函數(shù)耗時(shí)過長
更势胍:Lint跟LayoutInspector 對應(yīng) 檢測布局重繪問題,減少無用資源問題
更小: Progurad 減少無用代碼,壓縮資源