高質(zhì)量的應(yīng)用目標:快、穩(wěn)、省、小
快:使用時避免出現(xiàn)卡頓,響應(yīng)速度快,減少用戶等待的時間,滿足用戶期望。
穩(wěn):減低 crash 率和 ANR 率,不要在用戶使用過程中崩潰和無響應(yīng)。
?。汗?jié)省流量和耗電,減少用戶使用成本,避免使用時導(dǎo)致手機發(fā)燙。
?。喊惭b包小可以降低用戶的安裝成本

1. 卡頓優(yōu)化

歸根結(jié)底:顯示問題
Android系統(tǒng)顯示原理
應(yīng)用層繪制好后,通過跨進程通信把需要的數(shù)據(jù)傳遞到系統(tǒng)層,通過系統(tǒng)層的SurfaceFlinger把數(shù)據(jù)渲染到顯示屏幕上,通過Android的刷新機制來刷新數(shù)據(jù)。
應(yīng)用層
- View繪制核心步驟:Measure、Layout、Draw
- 從 ViewRootImp類的performTraversals() 方法開始執(zhí)行,Measure和Layout都是通過遞歸來獲取View的大小和位置,并且以深度作為優(yōu)先級,層級越深、元素越多、耗時也就越長。
繪制方式
- 軟件繪制(CPU)
- 硬件加速(GPU,3.0后全面支持)
應(yīng)用層GPU繪制缺點:
耗電
GPU功耗比CPU高兼容問題
某些接口和函數(shù)不支持硬件加速內(nèi)存大
使用OpenGL接口至少需要8MB內(nèi)存
繪制過程
- CPU準備數(shù)據(jù),通過Driver層把數(shù)據(jù)交給CPU渲染
- CPU主要負責(zé)Measure、Layout、Record、Execute的數(shù)據(jù)計算工作
GPU負責(zé)柵格化(Rasterization)、渲染 - 圖形API不允許CPU直接與GPU進行通信,通過圖形驅(qū)動層(Graphics Driver)來連接這兩部分
- 圖形驅(qū)動層維護了一個隊列,CPU把display list 添加到隊列中,GPU從中取出數(shù)據(jù)進行繪制,最終顯示。
系統(tǒng)層
通過系統(tǒng)級進程中的SurfaceFlinger服務(wù)來真正把需要顯示的數(shù)據(jù)渲染到屏幕上
響應(yīng)客戶端事件,創(chuàng)建Layer與客戶端的Surface建立連接。
接收客戶端數(shù)據(jù)及屬性,修改Layer屬性,如尺寸、顏色、透明度等。
將創(chuàng)建的Layer內(nèi)容刷新到屏幕上。
維持Layer的序列,并對Layer最終輸出做出裁剪計算。

應(yīng)用層繪制到緩存區(qū),SurfaceFlinger把緩存區(qū)數(shù)據(jù)渲染到屏幕,由于是不同的進程,所以使用Android的匿名共享內(nèi)存SharedClient緩存需要顯示的數(shù)據(jù)來達到目的。
FPS表示每秒傳遞的幀數(shù)。Android系統(tǒng)每隔16ms發(fā)出VSYNC信號,觸發(fā)對UI進行渲染。主要場景執(zhí)行動畫或滑動ListView。
CPU或GPU負載過重,布局過于復(fù)雜,16ms不能進行渲染,UI層疊太多,動畫執(zhí)行次數(shù)過多,刷新不及時等容易丟幀。
刷新機制
雙緩沖
Framebuffer帶來殘影問題
VSYNC(Vertical Synchronization)
CPU主動查詢保證數(shù)據(jù)是否準備好,效率低
定時中斷,收到信號,CPU處理各幀數(shù)據(jù)
Choreographer:起調(diào)度作用
收到VSYNC信號,調(diào)用用戶設(shè)置的回調(diào)函數(shù)
- CALLBACK_INPUT : 輸入事件有關(guān)
- CALLBACK_ANIMATION : 與動畫有關(guān)
- CALLBACK_TRAVERSAL : UI控件繪制有關(guān)
卡頓根本原因
- 繪制任務(wù)太重,繪制一幀內(nèi)容耗時太長
- 主線程太忙,根據(jù)系統(tǒng)傳遞過來的VSYNC信號來時還沒準備好數(shù)據(jù)導(dǎo)致丟幀。
主線程主要做以下幾個方面工作
- UI生命周期控制
- 系統(tǒng)事件處理
- 消息處理
- 界面布局
- 界面繪制
- 界面刷新
- 除此之外,應(yīng)該盡量避免將其他處理放在主線程中,特別復(fù)雜的數(shù)據(jù)計算和網(wǎng)絡(luò)請求等。
性能分析工具
1. Profile GPU Rendering
一個圖形監(jiān)測工具,能實時反應(yīng)當(dāng)前繪制的耗時
橫軸表示時間,縱軸表示每一幀的耗時
隨著時間推移,從左到右的刷新呈現(xiàn)
提供一個標準的耗時,如果高于標準耗時,就表示當(dāng)前這一幀丟失
可以通過adb shell dumpsys gfxinfo com..把具體耗時輸出到日志來進行查看分析

2. TraceView
TraceView是Android SDK自帶的工具,用來分析函數(shù)調(diào)用過程,可以對Android的應(yīng)用程序以及Framework層的代碼進行性能分析。
它是一個圖形化的工具,最終會產(chǎn)生一個圖表,用于對性能分析進行說明,可以分析到每一個方法的執(zhí)行時間,其中可以統(tǒng)計出該方法調(diào)用次數(shù)和遞歸次數(shù),實際時長等參數(shù)維度,使用非常直觀,分析性能非常方便。

3. Systrace

Systrace是Android 4.1及以上版本提供的性能數(shù)據(jù)采樣和分析工具,它是通過系統(tǒng)的角度來返回一些信息。
它可以幫助開發(fā)者收集Android關(guān)鍵子系統(tǒng),如Surfaceflinger、WindowManagerService等Framework部分關(guān)鍵模塊、服務(wù)、View系統(tǒng)等運行信息,從而幫助開發(fā)者更直觀地分析系統(tǒng)瓶頸,改進性能。
Systrace的功能包括跟蹤系統(tǒng)的I/O操作、內(nèi)核工作隊列、CPU負載等,在UI顯示性能分析上提供很好的數(shù)據(jù),特別是在動畫播放不流暢、渲染卡等問題上。
卡頓優(yōu)化建議
1 布局優(yōu)化(HieracrchyViewer&Lint)
- 減少層級。
- 合理使用RelativeLayout和LinerLayout,合理使用Merge。
- 提高顯示速度。
- 使用ViewStub。
- 布局復(fù)用。
- 通過標簽來提高復(fù)用。
- 盡可能少用wrap_content。
- 增加布局measure時計算成本,在已知寬高為固定值時,不用wrap_content
- 刪除控件中無用的屬性。
2 避免過度繪制
過度繪制
在屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次,從而浪費了多余的CPU以及GPU。
布局上的優(yōu)化:
- 移除XML中非必須的背景
- 移除Window默認的背景
- 按需顯示占位背景圖片
自定義View優(yōu)化:
使用 canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域,只有在這個區(qū)域內(nèi)才會被繪制。
開發(fā)者選項:調(diào)試GPU過度重繪
- 無色:1
- 藍色:1+
- 綠色:2+
- 淡紅:3+(不超過1/4屏可接受)
- 深紅:4++(嚴重影響性能,需優(yōu)化)

3 啟動優(yōu)化
通過對啟動速度的監(jiān)控,發(fā)現(xiàn)影響啟動速度的問題所在,優(yōu)化啟動邏輯,提高應(yīng)用的啟動速度。
啟動主要完成三件事:
UI布局
繪制
數(shù)據(jù)準備UI布局。
應(yīng)用一般都有閃屏頁,優(yōu)化閃屏頁的UI布局,可以通過Profile GPU Rendering檢測丟幀情況。使用HierarchyView檢查布局優(yōu)化啟動加載邏輯優(yōu)化。
可以采用分布加載、異步加載、延期加載策略來提高應(yīng)用啟動速度。

- 數(shù)據(jù)準備。
數(shù)據(jù)初始化分析,加載數(shù)據(jù)可以考慮用線程初始化等策略。
4 合理的刷新機制
頻繁刷新會增加資源開銷,并且可能導(dǎo)致卡頓發(fā)生,因此:
盡量減少刷新次數(shù)。
盡量避免后臺有高的CPU線程運行。
縮小刷新區(qū)域。
5 提升動畫性能
幀動畫:一組圖片按順序顯示。圖片過多,消耗資源,效果最差。
補間動畫:只需要定義開始和結(jié)束關(guān)鍵幀,之間效果自動生成。
局限性:
只能用于View對象,只有繼承于View或View的控件;
只有四種動畫:淡入淡出、縮放、平移、旋轉(zhuǎn)。
只改變了顯示效果,沒有改變真正屬性。屬性動畫:可以應(yīng)用于View,和任何對象。持續(xù)時間、時間插值、重復(fù)次數(shù)行為、動畫系和、幀刷新延遲。相對于不見動畫,重繪少,性能更佳。
在實現(xiàn)動畫效果時,需要根據(jù)不同場景選擇合適的動畫框架來實現(xiàn)。有些情況下,可以用硬件加速方式來提供流暢度。
2. 內(nèi)存優(yōu)化
Android內(nèi)存管理機制
Android應(yīng)用都是在 Android的虛擬機上運行,應(yīng)用程序的內(nèi)存分配與垃圾回收都是由虛擬機完成的。
在Android系統(tǒng),虛擬機有兩種運行模式:Dalvik和ART。
工具1 Memory Monitor
Memory Monitor是一款使用非常簡單的圖形化工具,可以很好地監(jiān)控系統(tǒng)或應(yīng)用的內(nèi)存使用情況,主要有以下功能:
- 顯示可用和已用內(nèi)存,并且以時間為維度實時反應(yīng)內(nèi)存分配和回收情況。
- 快速判斷應(yīng)用程序的運行緩慢是否由于過度的內(nèi)存回收導(dǎo)致。
- 快速判斷應(yīng)用是否由于內(nèi)存不足導(dǎo)致程序崩潰。
工具2 Heap Viewer
Heap Viewer的主要功能是查看不同數(shù)據(jù)類型在內(nèi)存中的使用情況,可以看到當(dāng)前進程中的Heap Size的情況,分別有哪些類型的數(shù)據(jù),以及各種類型數(shù)據(jù)占比情況。通過分析這些數(shù)據(jù)來找到大的內(nèi)存對象,再進一步分析這些大對象,進而通過優(yōu)化減少內(nèi)存開銷,也可以通過數(shù)據(jù)的變化發(fā)現(xiàn)內(nèi)存泄漏。
工具3 Allocation Tracker
Memory Monitor和Heap Viewer都可以很直觀且實時地監(jiān)控內(nèi)存使用情況,還能發(fā)現(xiàn)內(nèi)存問題,但發(fā)現(xiàn)內(nèi)存問題后不能再進一步找到原因,或者發(fā)現(xiàn)一塊異常內(nèi)存,但不能區(qū)別是否正常,同時在發(fā)現(xiàn)問題后,也不能定位到具體的類和方法。這時就需要使用另一個內(nèi)存分析工具Allocation Tracker,進行更詳細的分析,Allocation Tracker可以分配跟蹤記錄應(yīng)用程序的內(nèi)存分配,并列出了它們的調(diào)用堆棧,可以查看所有對象內(nèi)存分配的周期。
工具4 Memory Analyzer Tool(MAT)
MAT是一個快速,功能豐富的Java Heap分析工具,通過分析Java進程的內(nèi)存快照HPROF分析,從眾多的對象中分析,快速計算出在內(nèi)存中對象占用的大小,查看哪些對象不能被垃圾收集器回收,并可以通過視圖直觀地查看可能造成這種結(jié)果的對象。
常見內(nèi)存泄漏場景
資源性對象未關(guān)閉。比如Cursor、File文件等,往往都用了一些緩沖,在不使用時,應(yīng)該及時關(guān)閉它們。
注冊對象未注銷。比如事件注冊后未注銷,會導(dǎo)致觀察者列表中維持著對象的引用。
類的靜態(tài)變量持有大數(shù)據(jù)對象。
非靜態(tài)內(nèi)部類的靜態(tài)實例。
Handler臨時性內(nèi)存泄漏。如果Handler是非靜態(tài)的,容易導(dǎo)致Activity或Service不會被回收。
容器中的對象沒清理造成的內(nèi)存泄漏。
WebView。WebView存在著內(nèi)存泄漏的問題,在應(yīng)用中只要使用一次WebView,內(nèi)存就不會被釋放掉。
LeakCanary 第三方開源庫
這是一個檢測內(nèi)存泄漏的開源庫,可以在發(fā)生內(nèi)存泄漏時告警,并且生成leak tarce分析泄漏位置,同時可以提供Dump文件進行分析。
優(yōu)化內(nèi)存空間
對象引用。
強引用、軟引用、弱引用、虛引用四種引用類型,根據(jù)業(yè)務(wù)需求合理使用不同,選擇不同的引用類型。減少不必要的內(nèi)存開銷。
注意自動裝箱,增加內(nèi)存復(fù)用,比如有效利用系統(tǒng)自帶的資源、視圖復(fù)用、對象池、Bitmap對象的復(fù)用。使用最優(yōu)的數(shù)據(jù)類型。
比如針對數(shù)據(jù)類容器結(jié)構(gòu),可以使用ArrayMap數(shù)據(jù)結(jié)構(gòu),避免使用枚舉類型,使用緩存Lrucache等等。圖片內(nèi)存優(yōu)化。
可以設(shè)置位圖規(guī)格,根據(jù)采樣因子做壓縮,用一些圖片緩存方式對圖片進行管理等等。
3. 穩(wěn)定性優(yōu)化
提高代碼質(zhì)量。比如開發(fā)期間的代碼審核,看些代碼設(shè)計邏輯,業(yè)務(wù)合理性等。
代碼靜態(tài)掃描工具。常見工具有Android Lint、Findbugs、Checkstyle、PMD等等。
Crash監(jiān)控。把一些崩潰的信息,異常信息及時地記錄下來,以便后續(xù)分析解決。
Crash上傳機制。在Crash后,盡量先保存日志到本地,然后等下一次網(wǎng)絡(luò)正常時再上傳日志信息。
4. 耗電優(yōu)化
5.0之后專門引入了一個獲取設(shè)備上電量消耗信息的API:Battery Historian。一款由Google提供的Android系統(tǒng)電量圖形化數(shù)據(jù)分析工具,直觀地展示出手機的電量消耗過程,通過輸入電量分析文件,顯示消耗情況,最后提供一些可供參考電量優(yōu)化的方法。
計算優(yōu)化,避開浮點運算等。
避免WakeLock使用不當(dāng)。
休眠意味著CPU頻率降低,需要做一些需要大量運算的任務(wù)時,所以需要喚醒CPU使用JobScheduler
--
5. 安裝包大小瘦身
-
代碼混淆。
使用ProGuard代碼混淆器工具,它包括壓縮、優(yōu)化、混淆等功能。 -
資源優(yōu)化。
比如使用Android Lint刪除冗余資源,資源文件最少化等。 -
圖片優(yōu)化。
比如利用AAPT工具對PNG格式的圖片做壓縮處理,降低圖片色彩位數(shù)等。 - 避免重復(fù)功能的庫,使用WebP圖片格式等。
-
插件化。
比如功能模塊放在服務(wù)器上,按需下載,可以減少安裝包大小。